package l1j.server.server.model.skill;

import static l1j.server.server.model.skill.L1SkillId.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.opqlo.List.特殊列表;
import l1j.opqlo.NewSystem.L1AttackCancel;
import l1j.opqlo.Server.L1World.L1World;
import l1j.opqlo.Server.L1World.WorldWar;
import l1j.server.Config;
import l1j.server.server.ActionCodes;
import l1j.server.server.datatables.MapsTable;
import l1j.server.server.datatables.NpcTable;
import l1j.server.server.datatables.PolyTable;
import l1j.server.server.datatables.SkillsTable;
import l1j.server.server.model.L1Awake;
import l1j.server.server.model.L1CastleLocation;
import l1j.server.server.model.L1Character;
import l1j.server.server.model.L1CurseParalysis;
import l1j.server.server.model.L1EffectSpawn;
import l1j.server.server.model.L1Location;
import l1j.server.server.model.L1Magic;
import l1j.server.server.model.L1Object;
import l1j.server.server.model.L1PcInventory;
import l1j.server.server.model.L1PinkName;
import l1j.server.server.model.L1PolyMorph;
import l1j.server.server.model.L1Teleport;
import l1j.server.server.model.L1War;
import l1j.server.server.model.Instance.L1AuctionBoardInstance;
import l1j.server.server.model.Instance.L1BoardInstance;
import l1j.server.server.model.Instance.L1CrownInstance;
import l1j.server.server.model.Instance.L1DollInstance;
import l1j.server.server.model.Instance.L1DoorInstance;
import l1j.server.server.model.Instance.L1DwarfInstance;
import l1j.server.server.model.Instance.L1EffectInstance;
import l1j.server.server.model.Instance.L1FieldObjectInstance;
import l1j.server.server.model.Instance.L1FurnitureInstance;
import l1j.server.server.model.Instance.L1GuardInstance;
import l1j.server.server.model.Instance.L1HousekeeperInstance;
import l1j.server.server.model.Instance.L1ItemInstance;
import l1j.server.server.model.Instance.L1MerchantInstance;
import l1j.server.server.model.Instance.L1MonsterInstance;
import l1j.server.server.model.Instance.L1NpcInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.Instance.L1PetInstance;
import l1j.server.server.model.Instance.L1SummonInstance;
import l1j.server.server.model.Instance.L1TeleporterInstance;
import l1j.server.server.model.Instance.L1TowerInstance;
import l1j.server.server.model.poison.L1DamagePoison;
import l1j.server.server.model.trap.L1WorldTraps;
import l1j.server.server.serverpackets.S_ChangeHeading;
import l1j.server.server.serverpackets.S_ChangeName;
import l1j.server.server.serverpackets.S_ChangeShape;
import l1j.server.server.serverpackets.S_CharVisualUpdate;
import l1j.server.server.serverpackets.S_ChatPacket;
import l1j.server.server.serverpackets.S_CurseBlind;
import l1j.server.server.serverpackets.S_Dexup;
import l1j.server.server.serverpackets.S_DoActionGFX;
import l1j.server.server.serverpackets.S_DoActionShop;
import l1j.server.server.serverpackets.S_EffectLocation;
import l1j.server.server.serverpackets.S_HPUpdate;
import l1j.server.server.serverpackets.S_Invis;
import l1j.server.server.serverpackets.S_MPUpdate;
import l1j.server.server.serverpackets.S_Message_YN;
import l1j.server.server.serverpackets.S_NpcChatPacket;
import l1j.server.server.serverpackets.S_OwnCharAttrDef;
import l1j.server.server.serverpackets.S_OwnCharStatus;
import l1j.server.server.serverpackets.S_PacketBox;//TODO 暗影閃避byajackk2001
import l1j.server.server.serverpackets.S_Paralysis;
import l1j.server.server.serverpackets.S_Poison;
import l1j.server.server.serverpackets.S_RangeSkill;
import l1j.server.server.serverpackets.S_RemoveObject;
import l1j.server.server.serverpackets.S_SPMR;
import l1j.server.server.serverpackets.S_ServerMessage;
import l1j.server.server.serverpackets.S_ShowPolyList;
import l1j.server.server.serverpackets.S_ShowSummonList;
import l1j.server.server.serverpackets.S_SkillBrave;
import l1j.server.server.serverpackets.S_SkillHaste;
import l1j.server.server.serverpackets.S_SkillIconAura;
import l1j.server.server.serverpackets.S_SkillIconGFX;
import l1j.server.server.serverpackets.S_SkillIconShield;
import l1j.server.server.serverpackets.S_SkillIconWindShackle;
import l1j.server.server.serverpackets.S_SkillSound;
import l1j.server.server.serverpackets.S_Sound;
import l1j.server.server.serverpackets.S_Strup;
import l1j.server.server.serverpackets.S_UseAttackSkill;
import l1j.server.server.templates.L1BookMark;
import l1j.server.server.templates.L1Npc;
import l1j.server.server.templates.L1Skills;
import l1j.server.server.utils.Random;

public class L1SkillUse {


	public static final int TYPE_NORMAL = 0;
	public static final int TYPE_LOGIN = 1;
	public static final int TYPE_SPELLSC = 2;
	public static final int TYPE_NPCBUFF = 3;

	public static final int TYPE_GMBUFF = 4;
	private L1Skills _skill;
	private int _skillId;
	private int _getBuffDuration;
	private int _shockStunDuration;
	private int _getBuffIconDuration;
	private int _targetID;
	private int _mpConsume = 0;
	private int _hpConsume = 0;
	private int _targetX = 0;
	private int _targetY = 0;
	private int _skillTime = 0;
	private int _type = 0;
	private boolean _isPK = false;
	private int _bookmarkId = 0;
	private int _itemobjid = 0;
	private boolean _checkedUseSkill = false; // 事前チェック済みか
	private int _leverage = 10; // 1/10倍なので10で1倍
	private boolean _isFreeze = false;
	private boolean _isCounterMagic = true;

	private boolean _isGlanceCheckFail = false;
	private L1Character _user = null;

	private L1Character _target = null;
	private L1PcInstance _player = null;
	private L1NpcInstance _npc = null;

	private L1NpcInstance _targetNpc = null;
	private int _calcType;
	private static final int PC_PC = 1;
	private static final int PC_NPC = 2;
	private static final int NPC_PC = 3;

	private static final int NPC_NPC = 4;

	private ArrayList<TargetStatus> _targetList;

	private static Logger _log = Logger.getLogger(L1SkillUse.class.getName());

	// 不允許重複的技能組
	private static final int[][] repeatedSkills = {
		// ホーリー ウェポン、エンチャント ウェポン、ブレス ウェポン, シャドウ ファング
		// これらはL1ItemInstanceで管理
		// { HOLY_WEAPON, ENCHANT_WEAPON, BLESS_WEAPON, SHADOW_FANG },
		// ファイアー ウェポン、ウィンド ショット、ファイアー ブレス、ストーム アイ、バーニング ウェポン、ストーム ショット
		{ FIRE_WEAPON, WIND_SHOT, FIRE_BLESS, STORM_EYE, BURNING_WEAPON,STORM_SHOT },
		// シールド、シャドウ アーマー、アース スキン、アースブレス、アイアン スキン
		{ SHIELD, SHADOW_ARMOR, EARTH_SKIN, EARTH_BLESS, IRON_SKIN },
		// ホーリー ウォーク、ムービング アクセレーション、ウィンド ウォーク、BP、ワッフル、ユグドラの実、ブラッドラスト
		{ HOLY_WALK, MOVING_ACCELERATION, WIND_WALK, STATUS_BRAVE,
			STATUS_ELFBRAVE, STATUS_RIBRAVE, BLOODLUST,
			STATUS_THIRD_SPEED, STATUS_THIRD_SPEED2,
			STATUS_THIRD_SPEED3, STATUS_THIRD_SPEED4 },
			// ヘイスト、グレーター ヘイスト、GP
			{ HASTE, GREATER_HASTE, STATUS_HASTE, STATUS_THIRD_SPEED,
				STATUS_THIRD_SPEED2, STATUS_THIRD_SPEED3,
				STATUS_THIRD_SPEED4 },
				// フィジカル エンチャント：DEX、ドレス デクスタリティー
				{ PHYSICAL_ENCHANT_DEX, DRESS_DEXTERITY },
				// フィジカル エンチャント：STR、ドレス マイティー
				{ PHYSICAL_ENCHANT_STR, DRESS_MIGHTY },
				// グローウィングオーラ、シャイニングオーラ
				{ GLOWING_AURA, SHINING_AURA },
				// TODO 暗影閃避 鏡像byajackk2001
				{ MIRROR_IMAGE, UNCANNY_DODGE },
				// {CURSE_PARALYZE, SHOCK_STUN, },.
				{ EARTH_BIND, ICE_LANCE, FREEZING_BLIZZARD, FREEZING_BREATH,
					BONE_BREAK, FOG_OF_SLEEPING, STATUS_CHAT_PROHIBITED,
					NPC_FREEZING_BREATH } };

	public L1SkillUse() {
	}

	/**
	 * マジックリストに追加する。 使用相应技能要对玩家人物或者使用的相应道具追加必要动作
	 * */
	private void addMagicList(final L1Character cha, final boolean repetition) {
		if (this._skillTime == 0) {
			this._getBuffDuration = this._skill.getBuffDuration() * 1000; // 効果時間
			if (this._skill.getBuffDuration() == 0) {
				if (this._skillId == INVISIBILITY) { // インビジビリティ
					cha.setSkillEffect(INVISIBILITY, 0);
				}
				return;
			}
		} else {
			this._getBuffDuration = this._skillTime * 1000; // パラメータのtimeが0以外なら、効果時間として設定する
		}

		if (this._skillId == SHOCK_STUN) {
			this._getBuffDuration = this._shockStunDuration;
		}

		if (this._skillId == CURSE_POISON) { // カーズポイズンの効果処理はL1Poisonに移譲。
			return;
		}
		if (this._skillId == CURSE_PARALYZE || this._skillId == CURSE_PARALYZE2) { // カーズパラライズの効果処理はL1CurseParalysisに移譲。
			return;
		}
		if (this._skillId == SHAPE_CHANGE) { // シェイプチェンジの効果処理はL1PolyMorphに移譲。
			return;
		}
		if (this._skillId == BLESSED_ARMOR
				|| this._skillId == HOLY_WEAPON // 武器・防具に効果がある処理はL1ItemInstanceに移譲。
				|| this._skillId == ENCHANT_WEAPON
				|| this._skillId == BLESS_WEAPON
				|| this._skillId == SHADOW_FANG) {
			return;
		}
		if ((this._skillId == ICE_LANCE || this._skillId == FREEZING_BLIZZARD
				|| this._skillId == FREEZING_BREATH || this._skillId == NPC_FREEZING_BREATH)
				&& !this._isFreeze) { // 凍結失敗
			return;
		}
		if (this._skillId == AWAKEN_ANTHARAS
				|| this._skillId == AWAKEN_FAFURION
				|| this._skillId == AWAKEN_VALAKAS) { // 覚醒の効果処理はL1Awakeに移譲。
			return;
		}
		// 骷髏毀壞持續時間另外處理
		if (this._skillId == BONE_BREAK || this._skillId == CONFUSION) {
			return;
		}
		cha.setSkillEffect(this._skillId, this._getBuffDuration);
		if (this._skillId == ELEMENTAL_FALL_DOWN && repetition) { // 弱化屬性重複施放
			if (this._skillTime == 0) {
				this._getBuffIconDuration = this._skill.getBuffDuration(); // 効果時間
			} else {
				this._getBuffIconDuration = this._skillTime;
			}
			this._target.removeSkillEffect(ELEMENTAL_FALL_DOWN);
			this.runSkill();
			return;
		}
		if (cha instanceof L1PcInstance && repetition) { // 対象がPCで既にスキルが重複している場合
			final L1PcInstance pc = (L1PcInstance) cha;
			this.sendIcon(pc);
		}
	}

	/**
	 *
	 * @param player
	 *            攻擊者為PC
	 * @param skillid
	 *            技能編號
	 * @param target_id
	 *            目標OBJID
	 * @param x
	 *            X座標
	 * @param y
	 *            Y座標
	 * @param time
	 *            時間
	 * @param type
	 *            類型
	 * @param attacker
	 *            攻擊者為NPC
	 * @return
	 */
	public boolean checkUseSkill(final L1PcInstance player, final int skillid,
			final int target_id, final int x, final int y,
			final String message, final int time, final int type,
			final L1Character attacker) {
		// 初期設定ここから
		this.setCheckedUseSkill(true);
		this._targetList = new ArrayList<TargetStatus>(); // ターゲットリストの初期化

		this._skill = SkillsTable.getInstance().getTemplate(skillid);
		if (this._skill == null) {
			return false;
		}
		this._skillId = skillid;
		this._targetX = x;
		this._targetY = y;
		this._skillTime = time;
		this._type = type;
		boolean checkedResult = true;

		if (attacker == null) {
			// pc
			this._player = player;
			this._user = this._player;
		} else {
			// npc
			this._npc = (L1NpcInstance) attacker;
			this._user = this._npc;
		}

		if (this._skill.getTarget().equals("none")) {
			this._targetID = this._user.getId();
			this._targetX = this._user.getX();
			this._targetY = this._user.getY();
		} else {
			this._targetID = target_id;
		}

		if (type == TYPE_NORMAL) { // 通常の魔法使用時
			checkedResult = this.isNormalSkillUsable();
		} else if (type == TYPE_SPELLSC) { // スペルスクロール使用時
			checkedResult = this.isSpellScrollUsable();
		} else if (type == TYPE_NPCBUFF) {
			checkedResult = true;
		}
		if (!checkedResult) {
			return false;
		}

		// ファイアーウォール、ライフストリームは詠唱対象が座標
		// キューブは詠唱者の座標に配置されるため例外
		if (this._skillId == FIRE_WALL || this._skillId == LIFE_STREAM) {
			return true;
		}

		final L1Object l1object = L1World.getInstance().findObject(
				this._targetID);
		if (l1object instanceof L1ItemInstance) {
			_log.fine("skill target item name: "
					+ ((L1ItemInstance) l1object).getViewName());
			// スキルターゲットが精霊の石になることがある。
			// Linux環境で確認（Windowsでは未確認）
			// 2008.5.4追記：地面のアイテムに魔法を使うとなる。継続してもエラーになるだけなのでreturn
			return false;
		}
		if (this._user instanceof L1PcInstance) {
			if (l1object instanceof L1PcInstance) {
				this._calcType = PC_PC;
			} else {
				this._calcType = PC_NPC;
				this._targetNpc = (L1NpcInstance) l1object;
			}
		} else if (this._user instanceof L1NpcInstance) {
			if (l1object instanceof L1PcInstance) {
				this._calcType = NPC_PC;
			} else if (this._skill.getTarget().equals("none")) {
				this._calcType = NPC_PC;
			} else {
				this._calcType = NPC_NPC;
				this._targetNpc = (L1NpcInstance) l1object;
			}
		}

		// テレポート、マステレポートは対象がブックマークID
		if (this._skillId == TELEPORT || this._skillId == MASS_TELEPORT) {
			this._bookmarkId = target_id;
		}
		// 対象がアイテムのスキル
		if (this._skillId == CREATE_MAGICAL_WEAPON
				|| this._skillId == BRING_STONE
				|| this._skillId == BLESSED_ARMOR
				|| this._skillId == ENCHANT_WEAPON
				|| this._skillId == SHADOW_FANG) {
			this._itemobjid = target_id;
		}
		this._target = (L1Character) l1object;

		if (!(this._target instanceof L1MonsterInstance)
				&& this._skill.getTarget().equals("attack")
				&& this._user.getId() != target_id) {
			this._isPK = true; // ターゲットがモンスター以外で攻撃系スキルで、自分以外の場合PKモードとする。
		}

		// 初期設定ここまで

		// 事前チェック
		if (!(l1object instanceof L1Character)) { // ターゲットがキャラクター以外の場合何もしない。
			checkedResult = false;
		}
		this.makeTargetList(); // ターゲットの一覧を作成
		if (this._targetList.size() == 0 && this._user instanceof L1NpcInstance) {
			checkedResult = false;
		}
		// 事前チェックここまで
		return checkedResult;
	}

	/** 刪除重複的魔法狀態 */
	private void deleteRepeatedSkills(final L1Character cha) {

		// TODO 暗影閃避 鏡像byajackk2001
		for (final int[] skills : repeatedSkills) {
			for (final int id : skills) {
				if (id == this._skillId) {
					this.stopSkillList(cha, skills);
				}
			}
		}
	}
	private void detection(final L1PcInstance pc) {
		if (!pc.isGmInvis() && pc.isInvisble()) { // 自分
			pc.delInvis();
			pc.beginInvisTimer();
		}

		for (final L1PcInstance tgt : L1World.getInstance()
				.getVisiblePlayer(pc)) {
			if (!tgt.isGmInvis() && tgt.isInvisble()) {
				tgt.delInvis();
			}
		}
		// 偵測陷阱的處理
		L1WorldTraps.getInstance().onDetection(pc);
	}

	/**
	 * 施咒失敗処理(PCのみ）
	 */
	private void failSkill() {
		// HPが足りなくてスキルが使用できない場合のみ、MPのみ消費したいが未実装（必要ない？）
		// その他の場合は何も消費されない。
		// useConsume(); // HP、MPは減らす
		this.setCheckedUseSkill(false);
		// テレポートスキル
		if (this._skillId == TELEPORT || this._skillId == MASS_TELEPORT
				|| this._skillId == TELEPORT_TO_MATHER) {
			// テレポートできない場合でも、クライアント側は応答を待っている
			// テレポート待ち状態の解除（第2引数に意味はない）
			this._player.sendPackets(new S_Paralysis(S_Paralysis.TYPE_TELEPORT_UNLOCK, false));
		}
	}

	public L1Skills getL1Skills() {
		return this._skill;
	}

	public int getLeverage() {
		return this._leverage;
	}

	/**
	 * pc 用技能施放判斷
	 *
	 * @param player
	 * @param skillId
	 * @param targetId
	 * @param x
	 * @param y
	 * @param timeSecs
	 *            秒
	 * @param type
	 */
	public void handleCommands(final L1PcInstance player, final int skillId,
			final int targetId, final int x, final int y, final String message,
			final int timeSecs, final int type) {
		final L1Character attacker = null;
		this.handleCommands(player, skillId, targetId, x, y, message, timeSecs,
				type, attacker);
	}

	/**
	 * 通用技能施放判斷
	 *
	 * @param player
	 * @param skillId
	 * @param targetId
	 * @param x
	 * @param y
	 * @param timeSecs
	 * @param type
	 * @param attacker
	 */
	public void handleCommands(final L1PcInstance player, final int skillId,
			final int targetId, final int x, final int y, final String message,
			final int timeSecs, final int type, final L1Character attacker) {

		try {
			// 事前チェックをしているか？
			if (!this.isCheckedUseSkill()) {
				final boolean isUseSkill = this.checkUseSkill(player, skillId,
						targetId, x, y, message, timeSecs, type, attacker);

				if (!isUseSkill) {
					this.failSkill();
					return;
				}
			}

			if (type == TYPE_NORMAL) { // 魔法詠唱時
				if (!this._isGlanceCheckFail || this._skill.getArea() > 0
						|| this._skill.getTarget().equals("none")) {
					this.runSkill();
					this.useConsume();
					this.sendGrfx(true);
					this.sendFailMessageHandle();
					this.setDelay();
				}
			} else if (type == TYPE_LOGIN) { // ログイン時（HPMP材料消費なし、グラフィックなし）
				this.runSkill();
			} else if (type == TYPE_SPELLSC) { // スペルスクロール使用時（HPMP材料消費なし）
				this.runSkill();
				this.sendGrfx(true);
			} else if (type == TYPE_GMBUFF) { // GMBUFF使用時（HPMP材料消費なし、魔法モーションなし）
				this.runSkill();
				this.sendGrfx(false);
			} else if (type == TYPE_NPCBUFF) { // NPCBUFF使用時（HPMP材料消費なし）
				this.runSkill();
				this.sendGrfx(true);
			}
			this.setCheckedUseSkill(false);
		} catch (final Exception e) {
			_log.log(Level.SEVERE, "", e);
		}
	}

	// 精霊魔法の属性と使用者の属性は一致するか？（とりあえずの対処なので、対応できたら消去して下さい)
	private boolean isAttrAgrees() {
		final int magicattr = this._skill.getAttr();
		if (this._user instanceof L1NpcInstance) { // NPCが使った場合なんでもOK
			return true;
		}

		if (this._skill.getSkillLevel() >= 17
				&& this._skill.getSkillLevel() <= 22 && magicattr != 0 // 精霊魔法で、無属性魔法ではなく、
				&& magicattr != this._player.getElfAttr() // 使用者と魔法の属性が一致しない。
				&& !this._player.isGm()) { // ただしGMは例外
			return false;
		}
		return true;
	}

	private boolean isCheckedUseSkill() {
		return this._checkedUseSkill;
	}

	/**
	 * 判断技能的使用是否需要消耗HP/MP
	 *
	 * @return
	 */
	private boolean isHPMPConsume() {
		this._mpConsume = this._skill.getMpConsume();
		this._hpConsume = this._skill.getHpConsume();
		int currentMp = 0;
		int currentHp = 0;

		if (this._user instanceof L1NpcInstance) {
			currentMp = this._npc.getCurrentMp();
			currentHp = this._npc.getCurrentHp();
		} else {
			currentMp = this._player.getCurrentMp();
			currentHp = this._player.getCurrentHp();

			// MPのINT軽減
			final int getInt = this._player.getInt();

			if (getInt > 12 && this._skillId > HOLY_WEAPON
					&& this._skillId <= FREEZING_BLIZZARD) { // LV2以上
				this._mpConsume--;
			}
			if (getInt > 13 && this._skillId > STALAC
					&& this._skillId <= FREEZING_BLIZZARD) { // LV3以上
				this._mpConsume--;
			}
			if (getInt > 14 && this._skillId > WEAK_ELEMENTAL
					&& this._skillId <= FREEZING_BLIZZARD) { // LV4以上
				this._mpConsume--;
			}
			if (getInt > 15 && this._skillId > MEDITATION
					&& this._skillId <= FREEZING_BLIZZARD) { // LV5以上
				this._mpConsume--;
			}
			if (getInt > 16 && this._skillId > DARKNESS
					&& this._skillId <= FREEZING_BLIZZARD) { // LV6以上
				this._mpConsume--;
			}
			if (getInt > 17 && this._skillId > BLESS_WEAPON
					&& this._skillId <= FREEZING_BLIZZARD) { // LV7以上
				this._mpConsume--;
			}
			if (getInt > 18 && this._skillId > DISEASE
					&& this._skillId <= FREEZING_BLIZZARD) { // LV8以上
				this._mpConsume--;
			}

			if (getInt > 12 && this._skillId >= SHOCK_STUN
					&& this._skillId <= COUNTER_BARRIER) {
				this._mpConsume -= getInt - 12;
			}

			// MPの装備軽減
			if (this._skillId == PHYSICAL_ENCHANT_DEX
					&& this._player.getInventory().checkEquipped(20013)) { // 迅速ヘルム装備中にPE:DEX
				this._mpConsume /= 2;
			} else if (this._skillId == HASTE
					&& this._player.getInventory().checkEquipped(20013)) { // 迅速ヘルム装備中にヘイスト
				this._mpConsume /= 2;
			} else if (this._skillId == HEAL
					&& this._player.getInventory().checkEquipped(20014)) { // 治癒ヘルム装備中にヒール
				this._mpConsume /= 2;
			} else if (this._skillId == EXTRA_HEAL
					&& this._player.getInventory().checkEquipped(20014)) { // 治癒ヘルム装備中にエキストラヒール
				this._mpConsume /= 2;
			} else if (this._skillId == ENCHANT_WEAPON
					&& this._player.getInventory().checkEquipped(20015)) { // 力ヘルム装備中にエンチャントウエポン
				this._mpConsume /= 2;
			} else if (this._skillId == DETECTION
					&& this._player.getInventory().checkEquipped(20015)) { // 力ヘルム装備中にディテクション
				this._mpConsume /= 2;
			} else if (this._skillId == PHYSICAL_ENCHANT_STR
					&& this._player.getInventory().checkEquipped(20015)) { // 力ヘルム装備中にPE:STR
				this._mpConsume /= 2;
			} else if (this._skillId == HASTE
					&& this._player.getInventory().checkEquipped(20008)) { // マイナーウィンドヘルム装備中にヘイスト
				this._mpConsume /= 2;
			} else if (this._skillId == GREATER_HASTE
					&& this._player.getInventory().checkEquipped(20023)) { // ウィンドヘルム装備中にグレーターヘイスト
				this._mpConsume /= 2;
			}

			if (0 < this._skill.getMpConsume()) { // MPを消費するスキルであれば
				this._mpConsume = Math.max(this._mpConsume, 1); // 最低でも1消費する。
			}

			// MPのオリジナルINT軽減
			if (this._player.getOriginalMagicConsumeReduction() > 0) {
				this._mpConsume -= this._player
						.getOriginalMagicConsumeReduction();
			}
		}

		if (currentHp < this._hpConsume + 1) {
			if (this._user instanceof L1PcInstance) {
				this._player.sendPackets(new S_ServerMessage(279));
			}
			return false;
		} else if (currentMp < this._mpConsume) {
			if (this._user instanceof L1PcInstance) {
				this._player.sendPackets(new S_ServerMessage(278));
			}
			return false;
		}

		return true;
	}

	// 必要材料があるか？
	// 判断技能的使用是否需要其他物品的辅助
	private boolean isItemConsume() {

		final int itemConsume = this._skill.getItemConsumeId();
		final int itemConsumeCount = this._skill.getItemConsumeCount();

		if (itemConsume == 0) {
			return true; // 材料を必要としない魔法
		}

		if (!this._player.getInventory().checkItem(itemConsume,
				itemConsumeCount)) {
			return false; // 必要材料が足りなかった。
		}

		return true;
	}

	/**
	 * 通常のスキル使用時に使用者の状態からスキルが使用可能であるか判断する
	 *
	 * @return false スキルが使用不可能な状態である場合
	 */
	private boolean isNormalSkillUsable() {
		// スキル使用者がPCの場合のチェック
		if (this._user instanceof L1PcInstance) {
			final L1PcInstance pc = (L1PcInstance) this._user;

			if (pc.isParalyzed()) { // 麻痺・凍結状態か
				return false;
			}
			// if ((pc.isInvisble() || pc.isInvisDelay()) &&
			// !isInvisUsableSkill()) { // インビジ中に使用不可のスキル
			// return false;
			// }
			if (pc.getInventory().getWeight240() >= 197) { // 重量オーバーならスキルを使用できない
				pc.sendPackets(new S_ServerMessage(316));
				return false;
			}
			final int polyId = pc.getTempCharGfx();
			final L1PolyMorph poly = PolyTable.getInstance()
					.getTemplate(polyId);
			// 魔法が使えない変身
			if (poly != null && !poly.canUseSkill()) {
				pc.sendPackets(new S_ServerMessage(285)); // \f1その状態では魔法を使えません。
				return false;
			}

			if (!this.isAttrAgrees()) { // 精霊魔法で、属性が一致しなければ何もしない。
				return false;
			}

			if (this._skillId == ELEMENTAL_PROTECTION && pc.getElfAttr() == 0) {
				pc.sendPackets(new S_ServerMessage(280)); // \f1魔法が失敗しました。
				return false;
			}

			// スキルディレイ中使用不可
			if (pc.isSkillDelay()) {
				return false;
			}

			// 魔法封印、封印禁地、卡毒、幻想
			if (pc.hasSkillEffect(SILENCE)
					|| pc.hasSkillEffect(AREA_OF_SILENCE)
					|| pc.hasSkillEffect(STATUS_POISON_SILENCE)
					|| pc.hasSkillEffect(CONFUSION_ING)) {
				pc.sendPackets(new S_ServerMessage(285)); // \f1在此狀態下無法使用魔法。
				return false;
			}

			// DIGはロウフルでのみ使用可
			if (this._skillId == DISINTEGRATE && pc.getLawful() < 500) {
				// このメッセージであってるか未確認
				pc.sendPackets(new S_ServerMessage(352, "$967")); // 若要使用這個法術，屬性必須成為
				// (正義)。
				return false;
			}

			// 同じキューブは効果範囲外であれば配置可能
			if (this._skillId == CUBE_IGNITION || this._skillId == CUBE_QUAKE
					|| this._skillId == CUBE_SHOCK
					|| this._skillId == CUBE_BALANCE) {
				boolean isNearSameCube = false;
				int gfxId = 0;
				for (final L1Object obj : L1World.getInstance()
						.getVisibleObjects(pc, 3)) {
					if (obj instanceof L1EffectInstance) {
						final L1EffectInstance effect = (L1EffectInstance) obj;
						gfxId = effect.getGfxId();
						if (this._skillId == CUBE_IGNITION && gfxId == 6706
								|| this._skillId == CUBE_QUAKE && gfxId == 6712
								|| this._skillId == CUBE_SHOCK && gfxId == 6718
								|| this._skillId == CUBE_BALANCE
								&& gfxId == 6724) {
							isNearSameCube = true;
							break;
						}
					}
				}
				if (isNearSameCube) {
					pc.sendPackets(new S_ServerMessage(1412)); // 已在地板上召喚了魔法立方塊。
					return false;
				}
			}

			// 覚醒状態では覚醒スキル以外使用不可
			if (pc.getAwakeSkillId() == AWAKEN_ANTHARAS
					&& this._skillId != AWAKEN_ANTHARAS
					&& this._skillId != MAGMA_BREATH
					&& this._skillId != SHOCK_SKIN
					&& this._skillId != FREEZING_BREATH
					&& this._skillId != BURNING_SLASH
					&& this._skillId != GUARD_BRAKE
					&& this._skillId != BLOODLUST
					&& this._skillId != FOE_SLAYER
					&& this._skillId != RESIST_FEAR
					&& this._skillId != MORTAL_BODY
					&& this._skillId != THUNDER_GRAB
					&& this._skillId != HORROR_OF_DEATH

					|| pc.getAwakeSkillId() == AWAKEN_FAFURION
					&& this._skillId != AWAKEN_FAFURION
					&& this._skillId != MAGMA_BREATH
					&& this._skillId != SHOCK_SKIN
					&& this._skillId != FREEZING_BREATH
					&& this._skillId != BURNING_SLASH
					&& this._skillId != GUARD_BRAKE
					&& this._skillId != BLOODLUST
					&& this._skillId != FOE_SLAYER
					&& this._skillId != RESIST_FEAR
					&& this._skillId != MORTAL_BODY
					&& this._skillId != THUNDER_GRAB
					&& this._skillId != HORROR_OF_DEATH

					|| pc.getAwakeSkillId() == AWAKEN_VALAKAS
					&& this._skillId != AWAKEN_VALAKAS
					&& this._skillId != MAGMA_BREATH
					&& this._skillId != SHOCK_SKIN
					&& this._skillId != FREEZING_BREATH
					&& this._skillId != BURNING_SLASH
					&& this._skillId != GUARD_BRAKE
					&& this._skillId != BLOODLUST
					&& this._skillId != FOE_SLAYER
					&& this._skillId != RESIST_FEAR
					&& this._skillId != MORTAL_BODY
					&& this._skillId != THUNDER_GRAB
					&& this._skillId != HORROR_OF_DEATH) {
				pc.sendPackets(new S_ServerMessage(1385)); // 現在の状態では覚醒魔法が使えません。
				return false;
			}

			if (this.isItemConsume() == false && !this._player.isGm()) { // 法術消耗道具判斷。
				this._player.sendPackets(new S_ServerMessage(299)); // \f1施放魔法所需材料不足。
				return false;
			}
		}
		// スキル使用者がNPCの場合のチェック
		else if (this._user instanceof L1NpcInstance) {

			// サイレンス状態では使用不可
			if (this._user.hasSkillEffect(SILENCE)) {
				// NPCにサイレンスが掛かっている場合は1回だけ使用をキャンセルさせる効果。
				this._user.removeSkillEffect(SILENCE);
				return false;
			}
		}

		// PC、NPC共通檢查HP、MP是否足夠
		if (!this.isHPMPConsume()) { // 花費的HP、MP計算
			return false;
		}
		return true;
	}

	/**
	 * 被技能攻击而暂时不能解除
	 */
	private boolean isNotCancelable(final int skillNum) {
		return skillNum == ENCHANT_WEAPON || skillNum == BLESSED_ARMOR
				|| skillNum == ABSOLUTE_BARRIER || skillNum == ADVANCE_SPIRIT
				|| skillNum == SHOCK_STUN || skillNum == SHADOW_FANG
				|| skillNum == REDUCTION_ARMOR || skillNum == SOLID_CARRIAGE
				|| skillNum == COUNTER_BARRIER || skillNum == AWAKEN_ANTHARAS
				|| skillNum == AWAKEN_FAFURION || skillNum == AWAKEN_VALAKAS;
	}

	/**
	 * 目標對象 是否為寵物 召喚獸
	 *
	 * @param cha
	 * @return
	 */
	private boolean isPcSummonPet(final L1Character cha) {
		if (this._calcType == PC_PC) { // 対象がPC
			return true;
		}

		if (this._calcType == PC_NPC) {
			// 目標對象為召喚獸
			if (cha instanceof L1SummonInstance) {
				final L1SummonInstance summon = (L1SummonInstance) cha;
				// 目標對象具有主人
				if (summon.isExsistMaster()) {
					return true;
				}
			}
			// 目標對象為寵物
			if (cha instanceof L1PetInstance) {
				return true;
			}
		}
		return false;
	}

	/**
	 * スペルスクロール使用時に使用者の状態からスキルが使用可能であるか判断する
	 *
	 * @return false スキルが使用不可能な状態である場合
	 */
	private boolean isSpellScrollUsable() {
		// スペルスクロールを使用するのはPCのみ
		final L1PcInstance pc = (L1PcInstance) this._user;

		if (pc.isParalyzed()) { // 麻痺・凍結状態か
			return false;
		}

		// インビジ中に使用不可のスキル
		// if ((pc.isInvisble() || pc.isInvisDelay()) && !isInvisUsableSkill())
		// {
		// return false;
		// }

		return true;
	}

	// ターゲットか？
	private boolean isTarget(final L1Character cha) throws Exception {
		boolean _flg = false;
		// TODO 怪物的範圍負面魔法不會放到自己by9001183ex
		if (this._user instanceof L1MonsterInstance
				&& cha instanceof L1MonsterInstance
				&& this._skill.getType() == L1Skills.TYPE_PROBABILITY) {
			return false;
		}
		// TODO 怪物的範圍負面魔法不會放到自己by9001183ex
		if (cha instanceof L1PcInstance) {
			final L1PcInstance pc = (L1PcInstance) cha;
			if (pc.isGhost() || pc.isGmInvis()) {
				return false;
			}
		}
		if (this._calcType == NPC_PC
				&& (cha instanceof L1PcInstance || cha instanceof L1PetInstance || cha instanceof L1SummonInstance)) {
			_flg = true;
		}

		// TODO 修正召喚獸的範圍魔法by 阿傑的1098原碼
		if ((this._user instanceof L1PetInstance || this._user instanceof L1SummonInstance)
				&& (this._skill.getArea() > 0 || this._skillId == 17)) {
			if (this._user.glanceCheck(cha.getX(), cha.getY()) == true
					|| this._skill.isThrough() == true) {
				return cha instanceof L1MonsterInstance;
			}
		}
		// TODO 修正召喚獸的範圍魔法by 阿傑的1098原碼

		// 破壊不可能なドアは対象外
		if (cha instanceof L1DoorInstance) {
			if (cha.getMaxHp() == 0 || cha.getMaxHp() == 1) {
				return false;
			}
		}

		// マジックドールは対象外
		if (cha instanceof L1DollInstance && this._skillId != HASTE) {
			return false;
		}

		if (this._calcType == PC_NPC) {
			if (!(this._target instanceof L1NpcInstance)) {// 初始目標不是NPC
				return false;
			}
			if (!(this._target instanceof L1PetInstance) // 初始目標不是寵物
					&& !(this._target instanceof L1SummonInstance)) {// 初始目標不是召喚獸
				if (cha instanceof L1PetInstance // 範圍目標是寵物
						|| cha instanceof L1SummonInstance // 範圍目標是召喚獸
						|| cha instanceof L1PcInstance) {// 範圍目標是玩家
					return false; // 返回 不允許
				}
				if (!(this._target instanceof L1GuardInstance) // 初始目標不是守護者
						&& cha instanceof L1GuardInstance) {// 範圍目標是守護者
					return false;// 返回 不允許
				}
				if((this._target instanceof L1GuardInstance )){
					L1GuardInstance npc = (L1GuardInstance)this._target;
					if(npc.getNpcId() == 710061){
						return false;
					}
				} if(cha instanceof L1GuardInstance){
					L1GuardInstance npc = (L1GuardInstance)cha;
					if(npc.getNpcId() == 710061){
						return false;
					}
				}

			}
		}

		// 元のターゲットがPet、Summon以外のNPCの場合、PC、Pet、Summonは対象外
		/*
		 * if (_calcType == PC_NPC && _target instanceof L1NpcInstance
		 * //初始目標是NPC && !(_target instanceof L1PetInstance)//初始目標不是寵物 &&
		 * !(_target instanceof L1SummonInstance)//初始目標不是召喚獸 && (cha instanceof
		 * L1PetInstance || cha instanceof L1SummonInstance || cha instanceof
		 * L1PcInstance)) { return false; }
		 *
		 * // 元のターゲットがガード以外のNPCの場合、ガードは対象外 if (_calcType == PC_NPC && _target
		 * instanceof L1NpcInstance && !(_target instanceof L1GuardInstance) &&
		 * cha instanceof L1GuardInstance) { return false; }
		 */
		// NPC対PCでターゲットがモンスターの場合ターゲットではない。
		if ((this._skill.getTarget().equals("attack") || this._skill.getType() == L1Skills.TYPE_ATTACK)
				&& this._calcType == NPC_PC
				&& !(cha instanceof L1PetInstance)
				&& !(cha instanceof L1SummonInstance)
				&& !(cha instanceof L1PcInstance)) {
			return false;
		}

		// NPC対NPCで使用者がMOBで、ターゲットがMOBの場合ターゲットではない。
		if ((this._skill.getTarget().equals("attack") || this._skill.getType() == L1Skills.TYPE_ATTACK)
				&& this._calcType == NPC_NPC
				&& this._user instanceof L1MonsterInstance
				&& cha instanceof L1MonsterInstance) {
			return false;
		}

		// 無方向範囲攻撃魔法で攻撃できないNPCは対象外
		if (this._skill.getTarget().equals("none")
				&& this._skill.getType() == L1Skills.TYPE_ATTACK
				&& (cha instanceof L1AuctionBoardInstance
						|| cha instanceof L1BoardInstance
						|| cha instanceof L1CrownInstance
						|| cha instanceof L1DwarfInstance
						|| cha instanceof L1EffectInstance
						|| cha instanceof L1FieldObjectInstance
						|| cha instanceof L1FurnitureInstance
						|| cha instanceof L1HousekeeperInstance
						|| cha instanceof L1MerchantInstance || cha instanceof L1TeleporterInstance)) {
			return false;
		}

		// 攻撃系スキルで対象が自分は対象外
		if (this._skill.getType() == L1Skills.TYPE_ATTACK&& cha.getId() == this._user.getId()) {
			return false;
		}

		// 此治癒行為無法對自己施放
		if (cha.getId() == this._user.getId() && this._skillId == HEAL_ALL) {
			return false;
		}

		if (((this._skill.getTargetTo() & L1Skills.TARGET_TO_PC) == L1Skills.TARGET_TO_PC
				|| (this._skill.getTargetTo() & L1Skills.TARGET_TO_CLAN) == L1Skills.TARGET_TO_CLAN || (this._skill
						.getTargetTo() & L1Skills.TARGET_TO_PARTY) == L1Skills.TARGET_TO_PARTY)
						&& cha.getId() == this._user.getId()
						&& this._skillId != HEAL_ALL) {
			return true; // ターゲットがパーティーかクラン員のものは自分に効果がある。（ただし、ヒールオールは除外）
		}

		// スキル使用者がPCで、PKモードではない場合、自分のサモン・ペットは対象外
		if (this._user instanceof L1PcInstance
				&& (this._skill.getTarget().equals("attack") || this._skill
						.getType() == L1Skills.TYPE_ATTACK)
						&& this._isPK == false) {
			if (cha instanceof L1SummonInstance) {
				final L1SummonInstance summon = (L1SummonInstance) cha;
				if (this._player.getId() == summon.getMaster().getId()) {
					return false;
				}
			} else if (cha instanceof L1PetInstance) {
				final L1PetInstance pet = (L1PetInstance) cha;
				if (this._player.getId() == pet.getMaster().getId()) {
					return false;
				}
			}
		}

		if ((this._skill.getTarget().equals("attack") || this._skill.getType() == L1Skills.TYPE_ATTACK)
				&& !(cha instanceof L1MonsterInstance)
				&& this._isPK == false
				&& this._target instanceof L1PcInstance) {
			final L1PcInstance enemy = (L1PcInstance) cha;
			// カウンターディテクション
			if (this._skillId == COUNTER_DETECTION
					&& enemy.getZoneType() != 1
					&& (cha.hasSkillEffect(INVISIBILITY) || cha
							.hasSkillEffect(BLIND_HIDING))) {
				return true; // インビジかブラインドハイディング中
			}
			if (this._player.getClanid() != 0 && enemy.getClanid() != 0) { // クラン所属中
				// 全戦争リストを取得
				for (final L1War war : WorldWar.get().getWarList()) {
					if (war.checkClanInWar(this._player.getClanname())) { // 自クランが戦争に参加中
						if (war.checkClanInSameWar( // 同じ戦争に参加中
								this._player.getClanname(), enemy.getClanname())) {
							if (L1CastleLocation.checkInAllWarArea(
									enemy.getX(), enemy.getY(),
									enemy.getMapId())) {
								return true;
							}
						}
					}
				}
			}
			return false; // 攻撃スキルでPKモードじゃない場合
		}

		if (this._user.glanceCheck(cha.getX(), cha.getY()) == false
				&& this._skill.isThrough() == false) {
			// エンチャント、復活スキルは障害物の判定をしない
			if (!(this._skill.getType() == L1Skills.TYPE_CHANGE || this._skill
					.getType() == L1Skills.TYPE_RESTORE)) {
				this._isGlanceCheckFail = true;
				return false; // 直線上に障害物がある
			}
		}

		if (cha.hasSkillEffect(ICE_LANCE)
				&& (this._skillId == ICE_LANCE
				|| this._skillId == FREEZING_BLIZZARD
				|| this._skillId == FREEZING_BREATH || this._skillId == NPC_FREEZING_BREATH)) {
			return false; // アイスランス中にアイスランス、フリージングブリザード、フリージングブレス
		}

		if (cha.hasSkillEffect(FREEZING_BLIZZARD)
				&& (this._skillId == ICE_LANCE
				|| this._skillId == FREEZING_BLIZZARD || this._skillId == FREEZING_BREATH)) {
			return false; // フリージングブリザード中にアイスランス、フリージングブリザード、フリージングブレス
		}

		if (cha.hasSkillEffect(FREEZING_BREATH)
				&& (this._skillId == ICE_LANCE
				|| this._skillId == FREEZING_BLIZZARD || this._skillId == FREEZING_BREATH)) {
			return false; // フリージングブレス中にアイスランス、フリージングブリザード、フリージングブレス
		}

		if (cha.hasSkillEffect(EARTH_BIND) && this._skillId == EARTH_BIND) {
			return false; // アース バインド中にアース バインド
		}

		if (!(cha instanceof L1MonsterInstance)
				&& (this._skillId == TAMING_MONSTER || this._skillId == CREATE_ZOMBIE)) {
			return false; // ターゲットがモンスターじゃない（テイミングモンスター）
		}
		if (cha.isDead() && this._skillId != CREATE_ZOMBIE
				&& this._skillId != RESURRECTION
				&& this._skillId != GREATER_RESURRECTION
				&& this._skillId != CALL_OF_NATURE) {
			return false; // ターゲットが死亡している
		}

		if (cha.isDead() == false
				&& (this._skillId == CREATE_ZOMBIE
				|| this._skillId == RESURRECTION
				|| this._skillId == GREATER_RESURRECTION || this._skillId == CALL_OF_NATURE)) {
			return false; // ターゲットが死亡していない
		}

		if ((cha instanceof L1TowerInstance || cha instanceof L1DoorInstance)
				&& (this._skillId == CREATE_ZOMBIE
				|| this._skillId == RESURRECTION
				|| this._skillId == GREATER_RESURRECTION || this._skillId == CALL_OF_NATURE)) {
			return false; // ターゲットがガーディアンタワー、ドア
		}

		if (cha instanceof L1PcInstance) {
			final L1PcInstance pc = (L1PcInstance) cha;
			if (pc.hasSkillEffect(ABSOLUTE_BARRIER)) { // アブソルートバリア中
				if (this._skillId == CURSE_BLIND
						|| this._skillId == WEAPON_BREAK
						|| this._skillId == DARKNESS
						|| this._skillId == WEAKNESS
						|| this._skillId == DISEASE
						|| this._skillId == FOG_OF_SLEEPING
						|| this._skillId == MASS_SLOW || this._skillId == SLOW
						|| this._skillId == CANCELLATION
						|| this._skillId == SILENCE
						|| this._skillId == DECAY_POTION
						|| this._skillId == MASS_TELEPORT
						|| this._skillId == DETECTION
						|| this._skillId == COUNTER_DETECTION
						|| this._skillId == ERASE_MAGIC
						|| this._skillId == ENTANGLE
						|| this._skillId == PHYSICAL_ENCHANT_DEX
						|| this._skillId == PHYSICAL_ENCHANT_STR
						|| this._skillId == BLESS_WEAPON
						|| this._skillId == EARTH_SKIN
						|| this._skillId == IMMUNE_TO_HARM
						|| this._skillId == REMOVE_CURSE) {
					return true;
				} else {
					return false;
				}
			}
		}

		if (cha instanceof L1NpcInstance) {
			final int hiddenStatus = ((L1NpcInstance) cha).getHiddenStatus();
			if (hiddenStatus == L1NpcInstance.HIDDEN_STATUS_SINK) {
				if (this._skillId == DETECTION
						|| this._skillId == COUNTER_DETECTION) { // ディテク、Cディテク
					return true;
				} else {
					return false;
				}
			} else if (hiddenStatus == L1NpcInstance.HIDDEN_STATUS_FLY) {
				return false;
			}
		}

		if ((this._skill.getTargetTo() & L1Skills.TARGET_TO_PC) == L1Skills.TARGET_TO_PC // ターゲットがPC
				&& cha instanceof L1PcInstance) {
			_flg = true;
		} else if ((this._skill.getTargetTo() & L1Skills.TARGET_TO_NPC) == L1Skills.TARGET_TO_NPC // ターゲットがNPC
				&& (cha instanceof L1MonsterInstance
						|| cha instanceof L1NpcInstance
						|| cha instanceof L1SummonInstance || cha instanceof L1PetInstance)) {
			_flg = true;
		} else if ((this._skill.getTargetTo() & L1Skills.TARGET_TO_PET) == L1Skills.TARGET_TO_PET
				&& this._user instanceof L1PcInstance) { // ターゲットがSummon,Pet
			if (cha instanceof L1SummonInstance) {
				final L1SummonInstance summon = (L1SummonInstance) cha;
				if (summon.getMaster() != null) {
					if (this._player.getId() == summon.getMaster().getId()) {
						_flg = true;
					}
				}
			}
			if (cha instanceof L1PetInstance) {
				final L1PetInstance pet = (L1PetInstance) cha;
				if (pet.getMaster() != null) {
					if (this._player.getId() == pet.getMaster().getId()) {
						_flg = true;
					}
				}
			}
		}

		if (this._calcType == PC_PC && cha instanceof L1PcInstance) {
			if ((this._skill.getTargetTo() & L1Skills.TARGET_TO_CLAN) == L1Skills.TARGET_TO_CLAN
					&& (this._player.getClanid() != 0 // ターゲットがクラン員
					&& this._player.getClanid() == ((L1PcInstance) cha)
					.getClanid() || this._player.isGm())) {
				return true;
			}
			if ((this._skill.getTargetTo() & L1Skills.TARGET_TO_PARTY) == L1Skills.TARGET_TO_PARTY
					&& (this._player.getParty() .isMember((L1PcInstance) cha) // ターゲットがパーティー
							|| this._player.isGm())) {
				return true;
			}
		}

		return _flg;
	}

	/**
	 * 目標判定
	 *
	 * @param cha
	 * @param cha
	 * @return
	 */
	private boolean isTargetCalc(final L1Character cha) {
		// 攻撃魔法のNon－PvP判定
		if (this._skill.getTarget().equals("attack") && this._skillId != 18) { // 攻撃魔法
			if (this.isPcSummonPet(cha)) { // 対象がPC、サモン、ペット
				if (this._player.getZoneType() == 1 || cha.getZoneType() == 1 // 攻撃する側または攻撃される側がセーフティーゾーン
						|| this._player.checkNonPvP(this._player, cha)) { // Non-PvP設定
					return false;
				}
			}
		}

		// フォグオブスリーピングは自分自身は対象外
		if (this._skillId == FOG_OF_SLEEPING
				&& this._user.getId() == cha.getId()) {
			return false;
		}

		// マススローは自分自身と自分のペットは対象外
		if (this._skillId == MASS_SLOW) {
			if (this._user.getId() == cha.getId()) {
				return false;
			}
			if (cha instanceof L1SummonInstance) {
				final L1SummonInstance summon = (L1SummonInstance) cha;
				if (this._user.getId() == summon.getMaster().getId()) {
					return false;
				}
			} else if (cha instanceof L1PetInstance) {
				final L1PetInstance pet = (L1PetInstance) cha;
				if (this._user.getId() == pet.getMaster().getId()) {
					return false;
				}
			}
		}

		// マステレポートは自分自身のみ対象（同時にクラン員もテレポートさせる）
		if (this._skillId == MASS_TELEPORT) {
			if (this._user.getId() != cha.getId()) {
				return false;
			}
		}

		return true;
	}

	// ターゲットに対して必ず失敗になるか返す
	private boolean isTargetFailure(final L1Character cha) {
		boolean isTU = false;
		boolean isErase = false;
		boolean isManaDrain = false;
		int undeadType = 0;

		if (cha instanceof L1TowerInstance || cha instanceof L1DoorInstance) { // ガーディアンタワー、ドアには確率系スキル無効
			return true;
		}

		if (cha instanceof L1PcInstance) { // 対PCの場合
			if (this._calcType == PC_PC
					&& this._player.checkNonPvP(this._player, cha)) { // Non-PvP設定
				final L1PcInstance pc = (L1PcInstance) cha;
				if (this._player.getId() == pc.getId() || pc.getClanid() != 0
						&& this._player.getClanid() == pc.getClanid()) {
					return false;
				}
				return true;
			}
			return false;
		}

		if (cha instanceof L1MonsterInstance) { // ターンアンデット可能か判定
			isTU = ((L1MonsterInstance) cha).getNpcTemplate().get_IsTU();
		}

		if (cha instanceof L1MonsterInstance) { // イレースマジック可能か判定
			isErase = ((L1MonsterInstance) cha).getNpcTemplate().get_IsErase();
		}

		if (cha instanceof L1MonsterInstance) { // アンデットの判定
			undeadType = ((L1MonsterInstance) cha).getNpcTemplate()
					.get_undead();
		}

		// マナドレインが可能か？
		if (cha instanceof L1MonsterInstance) {
			isManaDrain = true;
		}
		/*
		 * 成功除外条件１：T-Uが成功したが、対象がアンデットではない。 成功除外条件２：T-Uが成功したが、対象にはターンアンデット無効。
		 * 成功除外条件３：スロー、マススロー、マナドレイン、エンタングル、イレースマジック、ウィンドシャックル無効
		 * 成功除外条件４：マナドレインが成功したが、モンスター以外の場合
		 */
		if (this._skillId == TURN_UNDEAD
				&& (undeadType == 0 || undeadType == 2)
				|| this._skillId == TURN_UNDEAD
				&& isTU == false
				|| (this._skillId == ERASE_MAGIC || this._skillId == SLOW
				|| this._skillId == MANA_DRAIN
				|| this._skillId == MASS_SLOW
				|| this._skillId == CURSE_PARALYZE
				|| this._skillId == ENTANGLE
				|| this._skillId == WIND_SHACKLE
				|| this._skillId == SHOCK_STUN
				|| this._skillId == BONE_BREAK || this._skillId == HASTE)
				&& isErase == false || this._skillId == MANA_DRAIN
				&& isManaDrain == false) {
			return true;
		}
		return false;
	}

	// カウンターマジックが発動したか返す
	private boolean isUseCounterMagic(final L1Character cha) {
		// カウンターマジック有効なスキルでカウンターマジック中
		if (this._isCounterMagic && cha.hasSkillEffect(COUNTER_MAGIC)) {
			cha.removeSkillEffect(COUNTER_MAGIC);
			final int castgfx = SkillsTable.getInstance()
					.getTemplate(COUNTER_MAGIC).getCastGfx();
			cha.broadcastPacketX8(new S_SkillSound(cha.getId(), castgfx));
			if (cha instanceof L1PcInstance) {
				final L1PcInstance pc = (L1PcInstance) cha;
				pc.sendPackets(new S_SkillSound(pc.getId(), castgfx));
			}
			return true;
		}
		return false;
	}

	// ターゲットの一覧を作成
	private void makeTargetList() {
		try {
			if (this._type == TYPE_LOGIN) { // ログイン時(死亡時、お化け屋敷のキャンセレーション含む)は使用者のみ
				this._targetList.add(new TargetStatus(this._user));
				return;
			}
			if (this._skill.getTargetTo() == L1Skills.TARGET_TO_ME
					&& (this._skill.getType() & L1Skills.TYPE_ATTACK) != L1Skills.TYPE_ATTACK) {
				this._targetList.add(new TargetStatus(this._user)); // ターゲットは使用者のみ
				return;
			}

			// 具有攻擊範圍設置
			if (this._skill.getRanged() != -1) {
				if (this._user.getLocation().getTileLineDistance(
						this._target.getLocation()) > this._skill.getRanged()) {
					return; // 射程範囲外
				}
			} else {
				// 距離不可見
				if (!this._user.getLocation().isInScreen(
						this._target.getLocation())) {
					return; // 射程範囲外
				}
			}

			if (this.isTarget(this._target) == false
					&& !this._skill.getTarget().equals("none")) {
				// 対象が違うのでスキルが発動しない。
				return;
			}

			// 直線上目標列舉
			switch (this._calcType) {
			case LIGHTNING:
			case FREEZING_BREATH:
				final ArrayList<L1Object> al1object = L1World.getInstance()
				.getVisibleLineObjects(this._user, this._target);
				for (final L1Object tgobj : al1object) {
					if (tgobj == null) {
						continue;
					}

					if (!(tgobj instanceof L1Character)) { // ターゲットがキャラクター以外の場合何もしない。
						continue;
					}

					final L1Character cha = (L1Character) tgobj;
					if (this.isTarget(cha) == false) {
						continue;
					}
					// 技能發動 目標清單判定:直線上目標列舉
					this._targetList.add(new TargetStatus(cha));
				}
				al1object.clear();
				return;
			}

			// 單一目標攻擊
			if (this._skill.getArea() == 0) {
				if (!this._user.glanceCheck(this._target.getX(),
						this._target.getY())) { // 直線上に障害物があるか
					if ((this._skill.getType() & L1Skills.TYPE_ATTACK) == L1Skills.TYPE_ATTACK
							&& this._skillId != 10026
							&& this._skillId != 10027
							&& this._skillId != 10028 && this._skillId != 10029) { // 安息攻撃以外の攻撃スキル
						this._targetList.add(new TargetStatus(this._target,
								false)); // ダメージも発生しないし、ダメージモーションも発生しないが、スキルは発動
						return;
					}
				}
				this._targetList.add(new TargetStatus(this._target));

				// 範圍攻擊
			} else {
				if (!this._skill.getTarget().equals("none")) {
					this._targetList.add(new TargetStatus(this._target));
				}

				if (this._skillId != 49
						&& !(this._skill.getTarget().equals("attack") || this._skill
								.getType() == L1Skills.TYPE_ATTACK)) {
					// 攻撃系以外のスキルとH-A以外はターゲット自身を含める
					this._targetList.add(new TargetStatus(this._user));
				}

				List<L1Object> objects;
				// 全畫面物件
				if (this._skill.getArea() == -1) {
					objects = L1World.getInstance().getVisibleObjects(
							this._user);

					// 指定範圍物件
				} else {
					objects = L1World.getInstance().getVisibleObjects(
							this._target, this._skill.getArea());
				}
				// System.out.println("攻擊範圍物件數量:"+objects.size());
				int count = 0;
				for (final L1Object tgobj : objects) {
					if (tgobj == null) {
						continue;
					}
					if (!(tgobj instanceof L1Character)) { // ターゲットがキャラクター以外の場合何もしない。
						continue;
					}
					final L1Character cha = (L1Character) tgobj;
					if (!this.isTarget(cha)) {
						continue;
					}
					/**** opqlo 範圍法術最大目標限制 *****/
					// System.out.println(count);
					// 技能發動 目標清單判定:加入目標清單 - 迴圈
					this._targetList.add(new TargetStatus(cha));
					count++;
					if (count >= 15) {
						break;
					}
				}
				return;
			}
		} catch (final Exception e) {
			_log.finest("exception in L1Skilluse makeTargetList" + e);
		}
	}

	/**
	 * 重複的狀態不做實際消除動作
	 * */
	private boolean Repetition(final L1PcInstance pc) {

		if (pc.hasSkillEffect(this._skillId)) {
			return true;
		}
		return false;
	}

	/**
	 * 發動技能效果
	 */
	private void runSkill() {

		switch (this._skillId) {
		case LIFE_STREAM:// 法師技能(治癒能量風暴)
			L1EffectSpawn.getInstance().spawnEffect(81169,
					this._skill.getBuffDuration() * 1000, this._targetX,
					this._targetY, this._user.getMapId(),
					(L1PcInstance) this._user);
			return;
		case CUBE_IGNITION:// 幻術師技能(立方：燃燒)
			L1EffectSpawn.getInstance().spawnEffect(80149,
					this._skill.getBuffDuration() * 1000, this._targetX,
					this._targetY, this._user.getMapId(),
					(L1PcInstance) this._user, this._skillId);
			return;
		case CUBE_QUAKE:// 幻術師技能(立方：地裂)
			L1EffectSpawn.getInstance().spawnEffect(80150,
					this._skill.getBuffDuration() * 1000, this._targetX,
					this._targetY, this._user.getMapId(),
					(L1PcInstance) this._user, this._skillId);
			return;
		case CUBE_SHOCK:// 幻術師技能(立方：衝擊)
			L1EffectSpawn.getInstance().spawnEffect(80151,
					this._skill.getBuffDuration() * 1000, this._targetX,
					this._targetY, this._user.getMapId(),
					(L1PcInstance) this._user, this._skillId);
			return;
		case CUBE_BALANCE:// 幻術師技能(立方：和諧)
			L1EffectSpawn.getInstance().spawnEffect(80152,
					this._skill.getBuffDuration() * 1000, this._targetX,
					this._targetY, this._user.getMapId(),
					(L1PcInstance) this._user, this._skillId);
			return;
		case FIRE_WALL: // 法師技能(火牢)
			L1EffectSpawn.getInstance().doSpawnFireWall(this._user,
					this._targetX, this._targetY);
			return;
		default:
			break;
		}

		// 魔法屏障不可抵擋的魔法
		if(特殊列表.get().isExceptMagic(this._skillId)){
			this._isCounterMagic = false; // 消除魔法無效
		}

		// NPCにショックスタンを使用させるとonActionでNullPointerExceptionが発生するため
		// とりあえずPCが使用した時のみ
		if (this._skillId == SHOCK_STUN && this._user instanceof L1PcInstance) {
			this._target.onAction(this._player);
		}

		if (!this.isTargetCalc(this._target)) {
			return;
		}

		try {
			TargetStatus ts = null;
			L1Character cha = null;
			int dmg = 0;
			int drainMana = 0;
			int heal = 0;
			boolean isSuccess = false;
			int undeadType = 0;

			for (final Iterator<TargetStatus> iter = this._targetList.iterator(); iter.hasNext();) {
				ts = null;
				cha = null;
				dmg = 0;
				heal = 0;
				isSuccess = false;
				undeadType = 0;

				ts = iter.next();
				cha = ts.getTarget();

				if (!ts.isCalc() || !this.isTargetCalc(cha)) {
					continue; // 計算する必要がない。
				}

				final L1Magic _magic = new L1Magic(this._user, cha);
				_magic.setLeverage(this.getLeverage());

				if (cha instanceof L1MonsterInstance) { // 不死係判斷
					undeadType = ((L1MonsterInstance) cha).getNpcTemplate()
							.get_undead();
				}

				// 確率系スキルで失敗が確定している場合
				if ((this._skill.getType() == L1Skills.TYPE_CURSE || this._skill
						.getType() == L1Skills.TYPE_PROBABILITY)
						&& this.isTargetFailure(cha)) {
					iter.remove();
					continue;
				}

				if (cha instanceof L1PcInstance) { // 只有在目标为pc的情况下发送图标，代表使用成功
					if (this._skillTime == 0) {
						this._getBuffIconDuration = this._skill
								.getBuffDuration(); // 効果時間
					} else {
						this._getBuffIconDuration = this._skillTime; // パラメータのtimeが0以外なら、効果時間として設定する
					}
				}

				this.deleteRepeatedSkills(cha); // 刪除重複的魔法狀態

				switch (this._skill.getType()) {
				case L1Skills.TYPE_ATTACK:
					if (this._user.getId() != cha.getId()) {
						if (this.isUseCounterMagic(cha)) { // カウンターマジックが発動した場合、リストから削除
							iter.remove();
							continue;
						}
						dmg = _magic.calcMagicDamage(this._skillId);
						cha.removeSkillEffect(ERASE_MAGIC); // イレースマジック中なら、攻撃魔法で解除
					}
					break;

				case L1Skills.TYPE_CURSE:
				case L1Skills.TYPE_PROBABILITY:
					if (this._type == TYPE_GMBUFF) {
						isSuccess = true;
					} else {
						isSuccess = _magic.calcProbabilityMagic(this._skillId);
					}
					if (this._skillId != ERASE_MAGIC) {
						cha.removeSkillEffect(ERASE_MAGIC); // イレースマジック中なら、確率魔法で解除
					}
					if (this._skillId != FOG_OF_SLEEPING) {
						cha.removeSkillEffect(FOG_OF_SLEEPING); // フォグオブスリーピング中なら、確率魔法で解除
					}
					if (isSuccess) { // 成功したがカウンターマジックが発動した場合、リストから削除
						if (this.isUseCounterMagic(cha)) { // カウンターマジックが発動したか
							iter.remove();
							continue;
						}
					} else { // 失敗した場合、リストから削除
						if (this._skillId == FOG_OF_SLEEPING
								&& cha instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) cha;
							pc.sendPackets(new S_ServerMessage(297)); // 軽いめまいを覚えました。
						}
						iter.remove();
						continue;
					}
					break;

				case L1Skills.TYPE_HEAL: // 治癒性魔法
					// 回復量はマイナスダメージで表現
					dmg = -1 * _magic.calcHealing(this._skillId);
					if (cha.hasSkillEffect(WATER_LIFE)) { // 水之元氣-效果 2倍
						dmg *= 2;
						cha.killSkillEffectTimer(WATER_LIFE); // 效果只有一次
					}
					if (cha.hasSkillEffect(POLLUTE_WATER)) {// 汙濁之水-效果減半
						dmg /= 2;
					}
					/**opqlo 不可對硬皮怪物補血*/
					if(cha instanceof L1MonsterInstance && this._user instanceof L1PcInstance){
						final L1MonsterInstance npc = (L1MonsterInstance)cha;
						if(npc.getDmgReduceRate() == 100){
							dmg = 0;
						}
					}
					break;

				}

				/*
				 * if (_skill.getType() == L1Skills.TYPE_ATTACK && _user.getId()
				 * != cha.getId()) { // 攻撃系スキル＆ターゲットが使用者以外であること。 if
				 * (isUseCounterMagic(cha)) { // カウンターマジックが発動した場合、リストから削除
				 * iter.remove(); continue; } dmg =
				 * _magic.calcMagicDamage(_skillId);
				 * cha.removeSkillEffect(ERASE_MAGIC); // イレースマジック中なら、攻撃魔法で解除 }
				 * else if (_skill.getType() == L1Skills.TYPE_CURSE||
				 * _skill.getType() == L1Skills.TYPE_PROBABILITY) { // 確率系スキル
				 * isSuccess = _magic.calcProbabilityMagic(_skillId); if
				 * (_skillId != ERASE_MAGIC) {
				 * cha.removeSkillEffect(ERASE_MAGIC); // イレースマジック中なら、確率魔法で解除 }
				 * if (_skillId != FOG_OF_SLEEPING) {
				 * cha.removeSkillEffect(FOG_OF_SLEEPING); //
				 * フォグオブスリーピング中なら、確率魔法で解除 } if (isSuccess) { //
				 * 成功したがカウンターマジックが発動した場合、リストから削除 if (isUseCounterMagic(cha)) {
				 * // カウンターマジックが発動したか iter.remove(); continue; } } else { //
				 * 失敗した場合、リストから削除 if (_skillId == FOG_OF_SLEEPING && cha
				 * instanceof L1PcInstance) { final L1PcInstance pc =
				 * (L1PcInstance) cha; pc.sendPackets(new S_ServerMessage(297));
				 * // 軽いめまいを覚えました。 } iter.remove(); continue; } } else if
				 * (_skill.getType() == L1Skills.TYPE_HEAL) { // 治癒性魔法 //
				 * 回復量はマイナスダメージで表現 dmg = -1 * _magic.calcHealing(_skillId); if
				 * (cha.hasSkillEffect(WATER_LIFE)) { // 水之元氣-效果 2倍 dmg *= 2;
				 * cha.killSkillEffectTimer(WATER_LIFE); // 效果只有一次 } if
				 * (cha.hasSkillEffect(POLLUTE_WATER)) {// 汙濁之水-效果減半 dmg /= 2; }
				 * }
				 */

				// ■■■■ 個別処理のあるスキルのみ書いてください。 ■■■■

				// 除了衝暈、骷髏毀壞之外魔法效果存在時，只更新效果時間跟圖示。
				if (cha.hasSkillEffect(this._skillId)
						&& this._skillId != SHOCK_STUN
						&& this._skillId != BONE_BREAK
						&& this._skillId != CONFUSION
						&& this._skillId != THUNDER_GRAB) {
					this.addMagicList(cha, true); // 魔法效果已存在時
					if (this._skillId != SHAPE_CHANGE) { // 除了變形術之外
						continue;
					}
				}
				// ●●●● PC、NPC両方効果のあるスキル ●●●●
				if (this._skillId == HASTE) { // ヘイスト
					if (cha.getMoveSpeed() != 2) { // スロー中以外
						if (cha instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) cha;
							if (pc.getHasteItemEquipped() > 0) {
								continue;
							}
							pc.setDrink(false);
							pc.sendPackets(new S_SkillHaste(pc.getId(), 1,this._getBuffIconDuration));
						}
						cha.broadcastPacketAll(new S_SkillHaste(cha.getId(), 1, 0));
						cha.setMoveSpeed(1);
					} else { // スロー中
						int skillNum = 0;
						if (cha.hasSkillEffect(SLOW)) {
							skillNum = SLOW;
						} else if (cha.hasSkillEffect(MASS_SLOW)) {
							skillNum = MASS_SLOW;
						} else if (cha.hasSkillEffect(ENTANGLE)) {
							skillNum = ENTANGLE;
						}
						if (skillNum != 0) {
							cha.removeSkillEffect(skillNum);
							cha.removeSkillEffect(HASTE);
							cha.setMoveSpeed(0);
							continue;
						}
					}
				} else if (this._skillId == CURE_POISON) {
					cha.curePoison();
				} else if (this._skillId == REMOVE_CURSE) {
					cha.curePoison();
					if (cha.hasSkillEffect(STATUS_CURSE_PARALYZING)
							|| cha.hasSkillEffect(STATUS_CURSE_PARALYZED)) {
						cha.cureParalaysis();
					}
				} else if (this._skillId == RESURRECTION
						|| this._skillId == GREATER_RESURRECTION) { // リザレクション、グレーターリザレクション
					if (cha instanceof L1PcInstance) {
						if(!MapsTable.getInstance().isUseResurrection(cha.getMapId())){
							_player.sendPackets(new S_ServerMessage(592));
							return;
						}
						final L1PcInstance pc = (L1PcInstance) cha;
						if (this._player.getId() != pc.getId()) {
							if (L1World.getInstance().getVisiblePlayer(pc, 0)
									.size() > 0) {
								for (final L1PcInstance visiblePc : L1World
										.getInstance().getVisiblePlayer(pc, 0)) {
									if (!visiblePc.isDead()) {
										// \f1その場所に他の人が立っているので復活させることができません。
										this._player
										.sendPackets(new S_ServerMessage(
												592));
										return;
									}
								}
							}
							if (pc.getCurrentHp() == 0 && pc.isDead()) {
								if (pc.getMap().isUseResurrection()) {
									if (this._skillId == RESURRECTION) {
										pc.setGres(false);
									} else if (this._skillId == GREATER_RESURRECTION) {
										pc.setGres(true);
									}
									pc.setTempID(this._player.getId());
									pc.sendPackets(new S_Message_YN(322, "")); // また復活したいですか？（Y/N）
								}
							}
						}
					}
					if (cha instanceof L1NpcInstance) {
						if (!(cha instanceof L1TowerInstance)) {
							final L1NpcInstance npc = (L1NpcInstance) cha;
							if (npc.getNpcTemplate().isCantResurrect()
									&& !(npc instanceof L1PetInstance)) {
								return;
							}
							if (npc instanceof L1PetInstance
									&& L1World.getInstance()
									.getVisiblePlayer(npc, 0).size() > 0) {
								for (final L1PcInstance visiblePc : L1World
										.getInstance().getVisiblePlayer(npc, 0)) {
									if (!visiblePc.isDead()) {
										// \f1その場所に他の人が立っているので復活させることができません。
										this._player
										.sendPackets(new S_ServerMessage(
												592));
										return;
									}
								}
							}
							if (npc.getCurrentHp() == 0 && npc.isDead()) {
								npc.resurrect(npc.getMaxHp() / 4);
								npc.setResurrect(true);
							}
						}
					}
					// TODO 生命呼喚
				} else if (this._skillId == CALL_OF_NATURE) { // コール オブ ネイチャー
					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;
						if (this._player.getId() != pc.getId()) {
							if (L1World.getInstance().getVisiblePlayer(pc, 0)
									.size() > 0) {
								for (final L1PcInstance visiblePc : L1World
										.getInstance().getVisiblePlayer(pc, 0)) {
									if (!visiblePc.isDead()) {
										// \f1その場所に他の人が立っているので復活させることができません。
										this._player
										.sendPackets(new S_ServerMessage(
												592));
										return;
									}
								}
							}
							if (pc.getCurrentHp() == 0 && pc.isDead()) {
								pc.setTempID(this._player.getId());
								pc.sendPackets(new S_Message_YN(322, "")); // また復活したいですか？（Y/N）
							}
						}
					}
					if (cha instanceof L1NpcInstance) {
						if (!(cha instanceof L1TowerInstance)) {
							final L1NpcInstance npc = (L1NpcInstance) cha;
							if (npc.getNpcTemplate().isCantResurrect()
									&& !(npc instanceof L1PetInstance)) {
								return;
							}
							if (npc instanceof L1PetInstance
									&& L1World.getInstance()
									.getVisiblePlayer(npc, 0).size() > 0) {
								for (final L1PcInstance visiblePc : L1World
										.getInstance().getVisiblePlayer(npc, 0)) {
									if (!visiblePc.isDead()) {
										// \f1その場所に他の人が立っているので復活させることができません。
										this._player
										.sendPackets(new S_ServerMessage(
												592));
										return;
									}
								}
							}
							if (npc.getCurrentHp() == 0 && npc.isDead()) {
								npc.resurrect(cha.getMaxHp());// HPを全回復する
								npc.resurrect(cha.getMaxMp() / 100);// MPを0にする
								npc.setResurrect(true);
							}
						}
					}
					// TODO 生命呼喚
				} else if (this._skillId == DETECTION) { // ディテクション
					if (cha instanceof L1NpcInstance) {
						final L1NpcInstance npc = (L1NpcInstance) cha;
						final int hiddenStatus = npc.getHiddenStatus();
						if (hiddenStatus == L1NpcInstance.HIDDEN_STATUS_SINK) {
							npc.appearOnGround(this._player);
						}
					}
				} else if (this._skillId == COUNTER_DETECTION) { // カウンターディテクション
					if (cha instanceof L1PcInstance) {
						dmg = _magic.calcMagicDamage(this._skillId);
					} else if (cha instanceof L1NpcInstance) {
						final L1NpcInstance npc = (L1NpcInstance) cha;
						final int hiddenStatus = npc.getHiddenStatus();
						if (hiddenStatus == L1NpcInstance.HIDDEN_STATUS_SINK) {
							npc.appearOnGround(this._player);
						} else {
							dmg = 0;
						}
					} else {
						dmg = 0;
					}
				} else if (this._skillId == TRUE_TARGET) { // トゥルーターゲット
					this._target.onAction(this._player);
					L1SpecialSkillAction.SpecialSkillAction(this._user, 1662,1662, 9); // 後面的9是攻擊距離
				} else if (this._skillId == CONFUSION) {// 混亂
					// 發動判斷
					if (this._user instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) this._user;
						if (!cha.hasSkillEffect(CONFUSION)) {
							pc.sendPacketsX8(new S_SkillSound(cha.getId(), 6525));
							cha.setSkillEffect(CONFUSION, 2 * 1000); // 發動後再次發動間隔
							// 2秒
							cha.setSkillEffect(CONFUSION_ING, 8 * 1000);
							if (cha instanceof L1PcInstance) {
								final L1PcInstance targetPc = (L1PcInstance) cha;
								targetPc.sendPackets(new S_ServerMessage(1339)); // 突然感覺到混亂。
							}

						}
					}
				} else if (this._skillId == PHANTASM) {
					if (!cha.hasSkillEffect(FOG_OF_SLEEPING)) {
						cha.setSkillEffect(FOG_OF_SLEEPING, 5000);
						if (cha instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) cha;
							pc.sendPackets(new S_Paralysis(
									S_Paralysis.TYPE_SLEEP, true));
						}
					}
				} else if (this._skillId == ELEMENTAL_FALL_DOWN) { // エレメンタルフォールダウン
					if (this._user instanceof L1PcInstance) {
						final int playerAttr = this._player.getElfAttr();
						final int i = -50;
						if (cha instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) cha;
							switch (playerAttr) {
							case 0:
								this._player
								.sendPackets(new S_ServerMessage(79));
								break;
							case 1:
								pc.addEarth(i);
								pc.setAddAttrKind(1);
								break;
							case 2:
								pc.addFire(i);
								pc.setAddAttrKind(2);
								break;
							case 4:
								pc.addWater(i);
								pc.setAddAttrKind(4);
								break;
							case 8:
								pc.addWind(i);
								pc.setAddAttrKind(8);
								break;
							default:
								break;
							}
						} else if (cha instanceof L1MonsterInstance) {
							final L1MonsterInstance mob = (L1MonsterInstance) cha;
							switch (playerAttr) {
							case 0:
								this._player
								.sendPackets(new S_ServerMessage(79));
								break;
							case 1:
								mob.addEarth(i);
								mob.setAddAttrKind(1);
								break;
							case 2:
								mob.addFire(i);
								mob.setAddAttrKind(2);
								break;
							case 4:
								mob.addWater(i);
								mob.setAddAttrKind(4);
								break;
							case 8:
								mob.addWind(i);
								mob.setAddAttrKind(8);
								break;
							default:
								break;
							}
						}
					}

					// ★★★ 回復系スキル ★★★
				}else if ((this._skillId == HEAL || this._skillId == EXTRA_HEAL
						|| this._skillId == GREATER_HEAL
						|| this._skillId == FULL_HEAL
						|| this._skillId == HEAL_ALL
						|| this._skillId == NATURES_TOUCH || this._skillId == NATURES_BLESSING)
						&& this._user instanceof L1PcInstance) {
					cha.removeSkillEffect(WATER_LIFE);

					// ★★★ 攻撃系スキル ★★★
					// チルタッチ、バンパイアリックタッチ
				}else if (this._skillId == CHILL_TOUCH
						|| this._skillId == VAMPIRIC_TOUCH) {
					if (cha instanceof L1MonsterInstance
							|| cha instanceof L1PcInstance) {
						// heal = Math.min(100, dmg);
						heal = Random.nextInt(dmg / (Random.nextInt(5) + 1)) + 1;
					} else {
						heal = 0;
					}
				} else if (this._skillId == TRIPLE_ARROW) { // トリプルアロー
					// 1回射出する毎にアロー、ダメージ、命中を計算する
					// アローが残り1でサイハの弓を持ってるとき、
					// 最初は普通の攻撃その後は魔法攻撃
					// アローが残り1で普通の弓を持ってるとき，最初は普通の攻撃，
					// その後はアローの射出を行わず動きだけを行う。

					// GFX Check (Made by HuntBoy)
					final int playerGFX = this._player.getTempCharGfx();
					if (!特殊列表.get().getBowGFX(playerGFX)) {
						return;
					}

					/* opqlo 狂斬臂甲 */
					boolean reTrue = false;
					if (this._player.AttackX3) {
						this._player.AttackX3 = false;
						reTrue = true;
					}// opqlo 三重矢中不帶入狂斬臂甲施展機率
					this._player.setSkillEffect(TRIPLE_ARROW, 3000);
					for (int i = 3; i > 0; i--) {
						this._target.onAction(this._player);
					}
					this._player.killSkillEffectTimer(TRIPLE_ARROW);
					this._player.sendPacketsX8(new S_SkillSound(this._player
							.getId(), 4394));
					// 三重矢結束後 恢復連斬臂甲功能
					if (reTrue) {
						this._player.AttackX3 = true;
					}

				} else if (this._skillId == FOE_SLAYER) {// TODO 屠宰者
					// TODO 給予屠宰者狀態，用於判斷是否加成30%傷害
					this._player.setSkillEffect(FOE_SLAYER, 5 * 1000);
					/* opqlo 狂斬臂甲 */
					boolean reTrue = false;
					if (this._player.AttackX3) {
						this._player.AttackX3 = false;
						reTrue = true;
					}// opqlo 三重矢中不帶入狂斬臂甲施展機率
					for (int i = 3; i > 0; i--) {
						this._target.onAction(this._player);
					}
					this._player.sendPacketsX8(new S_SkillSound(this._player
							.getId(), 7020));
					this._player.sendPacketsX8(new S_SkillSound(this._player
							.getId(), 6509));
					if (reTrue) {
						this._player.AttackX3 = true;
					}
					// TODO 施放屠宰者時，弱點曝光 LV1、LV2 消失
					if (this._player
							.hasSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV2)) {
						this._player
						.killSkillEffectTimer(SPECIAL_EFFECT_WEAKNESS_LV2);
						this._player.sendPackets(new S_SkillIconGFX(75, 0));
					} else if (this._player
							.hasSkillEffect(SPECIAL_EFFECT_WEAKNESS_LV1)) {
						this._player
						.killSkillEffectTimer(SPECIAL_EFFECT_WEAKNESS_LV1);
						this._player.sendPackets(new S_SkillIconGFX(75, 0));
					}
					// TODO 刪除屠宰者狀態
					this._player.killSkillEffectTimer(FOE_SLAYER);

				} else if (this._skillId == 10026 || this._skillId == 10027
						|| this._skillId == 10028 || this._skillId == 10029) {// 安息攻撃
					if (this._user instanceof L1NpcInstance) {
						this._user.broadcastPacketX8(new S_NpcChatPacket(this._npc, "$3717", 0)); // さあ、おまえに安息を与えよう。
					} else {
						this._player.broadcastPacketX8(new S_ChatPacket(
								this._player, "$3717", 0, 0)); // さあ、おまえに安息を与えよう。
					}
				} else if (this._skillId == 10057) { // 引き寄せ
					L1Teleport.teleportToTargetFront(cha, this._user, 1);
				}

				// ★★★ 確率系スキル ★★★
				else if (this._skillId == SLOW || this._skillId == MASS_SLOW
						|| this._skillId == ENTANGLE) { // スロー、マス
					// スロー、エンタングル
					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.setThirdSpeed(0);
						if (pc.hasSkillEffect(STATUS_THIRD_SPEED)){
							pc.setSpeedUp(false);
							pc.removeSkillEffect(STATUS_THIRD_SPEED);
						}else if (pc.hasSkillEffect(STATUS_THIRD_SPEED2)){
							pc.removeSkillEffect(STATUS_THIRD_SPEED2);
						}else if (pc.hasSkillEffect(STATUS_THIRD_SPEED3)){
							pc.setSpeedUp(false);
							pc.removeSkillEffect(STATUS_THIRD_SPEED3);
						}else if (pc.hasSkillEffect(STATUS_THIRD_SPEED4)){
							pc.removeSkillEffect(STATUS_THIRD_SPEED4);
						}
						if (pc.getHasteItemEquipped() > 0) {
							continue;
						}
					}
					if (cha.getMoveSpeed() == 0) {
						cha.setMoveSpeed(2);
						if (cha instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) cha;
							pc.sendPackets(new S_SkillHaste(pc.getId(), 2,this._getBuffIconDuration));
						}
						cha.broadcastPacketAll(new S_SkillHaste(cha.getId(), 2,this._getBuffIconDuration));
					} else if (cha.getMoveSpeed() == 1) {
						int skillNum = 0;
						if (cha.hasSkillEffect(HASTE)) {
							skillNum = HASTE;
						} else if (cha.hasSkillEffect(GREATER_HASTE)) {
							skillNum = GREATER_HASTE;
						} else if (cha.hasSkillEffect(STATUS_HASTE)) {
							skillNum = STATUS_HASTE;
						}
						if (skillNum != 0) {
							cha.setMoveSpeed(0);
							cha.removeSkillEffect(skillNum);
							cha.removeSkillEffect(this._skillId);
							continue;
						}
					}

				} else if (this._skillId == CURSE_BLIND
						|| this._skillId == DARKNESS) {
					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;
						if (pc.hasSkillEffect(STATUS_FLOATING_EYE)) {
							pc.sendPackets(new S_CurseBlind(2));
						} else {
							pc.sendPackets(new S_CurseBlind(1));
						}
					}
				} else if (this._skillId == CURSE_POISON) {
					L1DamagePoison.doInfection(this._user, cha, 3000, 5, false);
				} else if (this._skillId == CURSE_PARALYZE
						|| this._skillId == CURSE_PARALYZE2) {
					if (!L1AttackCancel.haveCancelSkill(cha)) {
						/*
						 * if (!cha.hasSkillEffect(EARTH_BIND) &&
						 * !cha.hasSkillEffect(ICE_LANCE) &&
						 * !cha.hasSkillEffect(FREEZING_BLIZZARD) &&
						 * !cha.hasSkillEffect(FREEZING_BREATH) &&
						 * !cha.hasSkillEffect(NPC_FREEZING_BREATH)) {
						 */
						if (cha instanceof L1PcInstance) {
							L1CurseParalysis.curse(cha, 8000, 16000, 1);
						} else if (cha instanceof L1MonsterInstance) {
							L1CurseParalysis.curse(cha, 0, 16000, 0);
						}
					}
				} else if (this._skillId == WEAKNESS) { // ウィークネス
					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addDmgup(-5);
						pc.addHitup(-1);
					}
				} else if (this._skillId == DISEASE) { // ディジーズ
					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addDmgup(-6);
						pc.addAc(12);
					}
				} else if (this._skillId == ALL_PARALYZE) {// opqlo 冰晶騎士 群體木乃伊
					for (final L1Object traget : L1World.getInstance().getVisibleObjects(this._user, 50)) {
						if (traget instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) traget;
							if (!L1AttackCancel.haveCancelSkill(pc)) {
								L1CurseParalysis.curse(cha, 5000, 8000, 2);
							}
						}
					}
				} else if (_skillId == 世界末日){
					for (final L1Object traget : L1World.getInstance().getVisibleObjects(this._user, 10)) {
						if (traget instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) traget;
							if(!pc.isDead() && !L1AttackCancel.haveCancelSkill(pc)){
								pc.setCurrentHp((int)(pc.getCurrentHp()/2));
							}
						}
					}
					this._user.broadcastPacketX8(new S_NpcChatPacket(this._npc, "我要毀滅世界!!", 0)); // さあ、おまえに安息を与えよう。
				} else if(_skillId == 死亡火焰){
					for (final L1Object traget : L1World.getInstance().getVisibleObjects(this._user, 10)) {
						if (traget instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) traget;
							if(!pc.isDead() && !L1AttackCancel.haveCancelSkill(pc)){
								pc.receiveDamage(_user, 1000000, false);
								pc.sendPacketsX10(new S_SkillSound(pc.getId() , 762));
							}
						}
					}
					this._user.broadcastPacketX8(new S_NpcChatPacket(this._npc, "燃燒殆盡!!", 0)); // さあ、おまえに安息を与えよう。
				} else if (this._skillId == NPC_CURSE_POISON) {// opqlo 吉爾塔斯 毒霧
					for (final L1Object traget : L1World.getInstance()
							.getVisibleObjects(this._user, 16)) {
						this._isFreeze = _magic
								.calcProbabilityMagic(this._skillId);
						if (this._isFreeze) {
							if (traget instanceof L1PcInstance
									|| traget instanceof L1SummonInstance
									|| traget instanceof L1PetInstance) {
								cha = (L1Character) traget;
								L1DamagePoison.doInfection(this._user, cha,1000, 200, true);
							}
						}
					}
				} else if (this._skillId == NPC_FREEZING_BREATH) {// opqlo 吉爾塔斯
					// 寒冰噴吐
					for (final L1Object traget : L1World.getInstance()
							.getVisibleObjects(this._user, 8)) {
						if (!(traget instanceof L1Character)) {
							continue;
						}
						this._isFreeze = _magic.calcProbabilityMagic(this._skillId);
						if (this._isFreeze && !cha.hasSkillEffect(SHOCK_STUN)) {

							cha = (L1Character) traget;
							final int time = this._skill.getBuffDuration() * 1000;
							if (cha instanceof L1PcInstance) {
								final L1PcInstance pc = (L1PcInstance) cha;
								pc.sendPacketsX8(new S_Poison(pc.getId(), 2));
								pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_FREEZE, true));
								pc.setSkillEffect(this._skillId, time);
								pc.setParalyzed(true);
								L1EffectSpawn.getInstance().spawnEffect(81168,time, cha.getX(), cha.getY(),cha.getMapId(), null);

							} else if (cha instanceof L1SummonInstance
									|| cha instanceof L1PetInstance) {
								final L1NpcInstance npc = (L1NpcInstance) cha;
								npc.broadcastPacketX8(new S_Poison(npc.getId(),2));
								npc.setParalyzed(true);
								npc.setParalysisTime(time);
								npc.setSkillEffect(this._skillId, time);
								L1EffectSpawn.getInstance().spawnEffect(81168,time, cha.getX(), cha.getY(),cha.getMapId(), (L1PcInstance) null);
							}
						}
					}
				} else if (this._skillId == ICE_LANCE // アイスランス
						|| this._skillId == FREEZING_BLIZZARD // フリージングブリザード
						|| this._skillId == FREEZING_BREATH) { // フリージングブレス
					this._isFreeze = _magic.calcProbabilityMagic(this._skillId);
					if (this._isFreeze && !cha.hasSkillEffect(SHOCK_STUN)) {
						final int time = this._skill.getBuffDuration() * 1000;
						if (this._user instanceof L1PcInstance) {
							L1EffectSpawn.getInstance().spawnEffect(81168,
									time, cha.getX(), cha.getY(),
									cha.getMapId(), (L1PcInstance) this._user);
						} else {
							L1EffectSpawn.getInstance().spawnEffect(81168,
									time, cha.getX(), cha.getY(),
									cha.getMapId(), (L1PcInstance) null);
						}
						if (cha instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) cha;
							pc.sendPacketsX8(new S_Poison(pc.getId(), 2));
							pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_FREEZE, true));
							pc.setParalyzed(true);
						} else if (cha instanceof L1MonsterInstance
								|| cha instanceof L1SummonInstance
								|| cha instanceof L1PetInstance) {
							final L1NpcInstance npc = (L1NpcInstance) cha;
							npc.broadcastPacketX8(new S_Poison(npc.getId(), 2));
							npc.setParalyzed(true);
							npc.setParalysisTime(time);
						}
					}
				} else if (this._skillId == EARTH_BIND) { // アースバインド
					if (!cha.hasSkillEffect(SHOCK_STUN)
							&& !cha.hasSkillEffect(STATUS_FREEZE)) {
						if (cha instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) cha;
							pc.sendPacketsX8(new S_Poison(pc.getId(), 2));
							pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_FREEZE, true));
							pc.setParalyzed(true);
						} else if (cha instanceof L1MonsterInstance
								|| cha instanceof L1SummonInstance
								|| cha instanceof L1PetInstance) {
							final L1NpcInstance npc = (L1NpcInstance) cha;
							npc.broadcastPacketX8(new S_Poison(npc.getId(), 2));
							npc.setParalyzed(true);
							npc.setParalysisTime(this._skill.getBuffDuration() * 1000);
						}
					}
				} else if (this._skillId == SHOCK_STUN) {
					if (!L1AttackCancel.haveCancelSkill(cha)
							&& !cha.hasSkillEffect(STATUS_FREEZE)) {
						final HashMap<Integer , Integer> SecList = 特殊列表.get().getSturnSEC();
						final int rnd = Random.nextInt(SecList.size());
						this._shockStunDuration = SecList.get(rnd)* Config.SHOCK_STUN_TIMER;// TODO 衝暈秒數
						if (cha instanceof L1PcInstance
								&& cha.hasSkillEffect(SHOCK_STUN)) {
							this._shockStunDuration += cha.getSkillEffectTimeSec(SHOCK_STUN) * 1000;
						}

						L1EffectSpawn.getInstance().spawnEffect(81162,
								this._shockStunDuration, cha.getX(),
								cha.getY(), cha.getMapId(), null);

						if (cha instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) cha;
							pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_STUN, true));
							pc.setParalyzed(true);
						} else if (cha instanceof L1MonsterInstance
								|| cha instanceof L1SummonInstance
								|| cha instanceof L1PetInstance) {
							final L1NpcInstance npc = (L1NpcInstance) cha;
							npc.setParalyzed(true);
							npc.setParalysisTime(this._shockStunDuration);
						}
					}
				} else if (this._skillId == THUNDER_GRAB) {// opqlo 奪命之雷
					if (!L1AttackCancel.haveCancelSkill(cha)
							&& !cha.hasSkillEffect(SHOCK_STUN)) {
						isSuccess = _magic.calcProbabilityMagic(this._skillId);
						if (isSuccess) {
							if (!cha.hasSkillEffect(THUNDER_GRAB_START)
									&& !cha.hasSkillEffect(STATUS_FREEZE)) {
								if (cha instanceof L1PcInstance) {
									final L1PcInstance pc = (L1PcInstance) cha;
									pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_BIND, true));
									pc.sendPacketsX8(new S_SkillSound(pc.getId(), 4184));
								} else if (cha instanceof L1NpcInstance) {
									final L1NpcInstance npc = (L1NpcInstance) cha;
									// 刪除npc.setParalyzed(false);//opqlo
									// 修正束縛術對怪物暈眩
									npc.setPassispeed(0); // opqlo 新增此行
									npc.broadcastPacketAll(new S_SkillSound(npc.getId(), 4184));
								}
								cha.setSkillEffect(THUNDER_GRAB_START, 500);
							}
						}
					}
				} else if (this._skillId == BONE_BREAK) {// opqlo 骷髏毀壞
					if (!L1AttackCancel.haveCancelSkill(cha)
							&& !cha.hasSkillEffect(SHOCK_STUN)) {
						final int change = Random.nextInt(10) + 1;
						if (change <= 4) { // 30 ~ 40%
							final int[] stunTimeArray = { 1000, 1200, 1400,
									1600, 1800, 2000 };
							final int rnd = Random
									.nextInt(stunTimeArray.length);
							this._shockStunDuration = stunTimeArray[rnd];
							/*
							 * if (cha instanceof L1PcInstance&&
							 * cha.hasSkillEffect(BONE_BREAK)) {
							 * _shockStunDuration +=
							 * cha.getSkillEffectTimeSec(BONE_BREAK) * 1000; }
							 */
							cha.setSkillEffect(BONE_BREAK,
									this._shockStunDuration);
							L1EffectSpawn.getInstance().spawnEffect(1234567,
									this._shockStunDuration, cha.getX(),
									cha.getY(), cha.getMapId(),
									(L1PcInstance) this._user);// 創造骷髏毀壞效果npc
							// （npc編號123456）
							if (cha instanceof L1PcInstance) {
								final L1PcInstance pc = (L1PcInstance) cha;// final
								pc.sendPackets(new S_Paralysis(
										S_Paralysis.TYPE_STUN, true));
								pc.setParalyzed(true);
							} else if (cha instanceof L1MonsterInstance
									|| cha instanceof L1SummonInstance
									|| cha instanceof L1PetInstance) {
								final L1NpcInstance npc = (L1NpcInstance) cha;// final
								npc.setParalyzed(true);
								npc.setParalysisTime(this._shockStunDuration);
							}
						}
					}
				} else if (this._skillId == WIND_SHACKLE) { // ウィンド シャックル
					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.sendPackets(new S_SkillIconWindShackle(pc.getId(),
								this._getBuffIconDuration));
					}
				} else if (this._skillId == CANCELLATION) {
					if (cha instanceof L1NpcInstance) {
						final L1NpcInstance npc = (L1NpcInstance) cha;
						final int npcId = npc.getNpcTemplate().get_npcId();
						if (npcId == 71092) { // 調査員
							if (npc.getGfxId() == npc.getTempCharGfx()) {
								npc.setTempCharGfx(1314);
								npc.broadcastPacketAll(new S_ChangeShape(npc
										.getId(), 1314));
								return;
							} else {
								return;
							}
						}
						if (npcId == 45640) { // ユニコーン
							if (npc.getGfxId() == npc.getTempCharGfx()) {
								npc.setCurrentHp(npc.getMaxHp());
								npc.setTempCharGfx(2332);
								npc.broadcastPacketAll(new S_ChangeShape(npc
										.getId(), 2332));
								npc.setName("$2103");
								npc.setNameId("$2103");
								npc.broadcastPacketAll(new S_ChangeName(npc
										.getId(), "$2103"));
							} else if (npc.getTempCharGfx() == 2332) {
								npc.setCurrentHp(npc.getMaxHp());
								npc.setTempCharGfx(2755);
								npc.broadcastPacketAll(new S_ChangeShape(npc
										.getId(), 2755));
								npc.setName("$2488");
								npc.setNameId("$2488");
								npc.broadcastPacketAll(new S_ChangeName(npc
										.getId(), "$2488"));
							}
						}
						if (npcId == 81209) { // ロイ
							if (npc.getGfxId() == npc.getTempCharGfx()) {
								npc.setTempCharGfx(4310);
								npc.broadcastPacketAll(new S_ChangeShape(npc
										.getId(), 4310));
								return;
							} else {
								return;
							}
						}
					}
					if (this._player != null && this._player.isInvisble()) {
						this._player.delInvis();
					}
					if (!(cha instanceof L1PcInstance)) {
						final L1NpcInstance npc = (L1NpcInstance) cha;
						npc.setMoveSpeed(0);
						npc.setBraveSpeed(0);
						npc.broadcastPacketAll(new S_SkillHaste(cha.getId(), 0, 0));
						npc.broadcastPacketAll(new S_SkillBrave(cha.getId(), 0, 0));
						npc.setWeaponBreaked(false);
						npc.setParalyzed(false);
						npc.setParalysisTime(0);
					}

					// スキルの解除
					for (int skillNum = SKILLS_BEGIN; skillNum <= SKILLS_END; skillNum++) {
						if (this.isNotCancelable(skillNum) && !cha.isDead()) {
							continue;
						}
						cha.removeSkillEffect(skillNum);
					}

					// ステータス強化、異常の解除
					cha.curePoison();
					cha.cureParalaysis();
					for (int skillNum = STATUS_BEGIN; skillNum <= STATUS_END; skillNum++) {
						if (skillNum == STATUS_CHAT_PROHIBITED // チャット禁止は解除しない
								|| skillNum == STATUS_CURSE_BARLOG // バルログの呪いは解除しない
								|| skillNum == STATUS_CURSE_YAHEE) { // ヤヒの呪いは解除しない
							continue;
						}
						cha.removeSkillEffect(skillNum);
					}

					if (cha instanceof L1PcInstance) {
					}

					// 料理の解除
					for (int skillNum = COOKING_BEGIN; skillNum <= COOKING_END; skillNum++) {
						if (this.isNotCancelable(skillNum)) {
							continue;
						}
						cha.removeSkillEffect(skillNum);
					}

					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;

						// アイテム装備による変身の解除
						L1PolyMorph.undoPoly(pc);
						pc.sendPackets(new S_CharVisualUpdate(pc));
						pc.broadcastPacketAll(new S_CharVisualUpdate(pc));

						// ヘイストアイテム装備時はヘイスト関連のスキルが何も掛かっていないはずなのでここで解除
						if (pc.getHasteItemEquipped() > 0) {
							pc.setMoveSpeed(0);
							pc.sendPackets(new S_SkillHaste(pc.getId(), 0, 0));
							pc.broadcastPacketAll(new S_SkillHaste(pc.getId(), 0,
									0));
						}
					}
					cha.removeSkillEffect(STATUS_FREEZE);// Freeze解除
					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.sendPackets(new S_CharVisualUpdate(pc));
						pc.broadcastPacketAll(new S_CharVisualUpdate(pc));
						if (pc.isPrivateShop()) {
							pc.sendPackets(new S_DoActionShop(pc.getId(),
									ActionCodes.ACTION_Shop, pc.getShopChat()));
							pc.broadcastPacketAll(new S_DoActionShop(pc.getId(),
									ActionCodes.ACTION_Shop, pc.getShopChat()));
						}
						if (this._user instanceof L1PcInstance) {
							L1PinkName.onAction(pc, this._user);
						}
					}
				} else if (this._skillId == TURN_UNDEAD // ターン アンデッド
						&& (undeadType == 1 || undeadType == 3)) {
					// ダメージを対象のHPとする。
					dmg = cha.getCurrentHp();
				} else if (this._skillId == MANA_DRAIN) { // マナ ドレイン
					final int chance = Random.nextInt(10) + 5;
					drainMana = chance + this._user.getInt() / 2;
					if (cha.getCurrentMp() < drainMana) {
						drainMana = cha.getCurrentMp();
					}
				} else if (this._skillId == WEAPON_BREAK) { // ウェポン ブレイク
					/*
					 * 対NPCの場合、L1Magicのダメージ算出でダメージ1/2としているので
					 * こちらには、対PCの場合しか記入しない。 損傷量は1~(int/3)まで
					 */
					if (this._calcType == PC_PC || this._calcType == NPC_PC) {
						if (cha instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) cha;
							final L1ItemInstance weapon = pc.getWeapon();
							if (weapon != null) {
								final int weaponDamage = Random
										.nextInt(this._user.getInt() / 3) + 1;
								// \f1あなたの%0が損傷しました。
								pc.sendPackets(new S_ServerMessage(268, weapon
										.getLogName()));
								pc.getInventory().receiveDamage(weapon,
										weaponDamage);
							}
						}
					} else {
						((L1NpcInstance) cha).setWeaponBreaked(true);
					}
				} else if (this._skillId == 集體沉睡){
					this._user.broadcastPacketX10(new S_NpcChatPacket(this._npc, "米斯塔吉歐!", 0)); // さあ、おまえに安息を与えよう。
					for (final L1PcInstance pc : L1World.getInstance().getVisiblePlayer(this._user, 10)) {//取回10格內的玩家
						if(!pc.isDead() && !L1AttackCancel.haveCancelSkill(pc)){
							pc.receiveDamage(_user, 10000, false);
							pc.sendPacketsX10(new S_SkillSound(pc.getId() , 760));
							pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_SLEEP,true));
							pc.setSkillEffect(FOG_OF_SLEEPING, 32 * 1000);
						}
					}
				} else if (this._skillId == FOG_OF_SLEEPING) {
					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_SLEEP,true));
					}
					cha.setSleeped(true);
				} else if (this._skillId == STATUS_FREEZE) { // Freeze
					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_BIND,
								true));
					}
				} else if (this._skillId == GUARD_BRAKE) { // ガードブレイク
					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addAc(10);// TODO 降低敵人防禦10點
					}
				} else if (this._skillId == HORROR_OF_DEATH) {// ホラーオブデス
					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addStr(-3);// TODO 力量-3
						pc.addInt(-3);// TODO 智量-3
					}
				}

				// ●●●● PCにしか効果のないスキル ●●●●
				if (this._calcType == PC_PC || this._calcType == NPC_PC) {
					// ★★★ 特殊系スキル★★★
					if (this._skillId == TELEPORT
							|| this._skillId == MASS_TELEPORT) { // マステレ、テレポート
						if (cha instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) cha;
							// 所在位置 是否允許傳送
							if (!pc.getMap().isTeleportable() && !pc.isGm()) {
								// 647 這附近的能量影響到瞬間移動。在此地無法使用瞬間移動。
								pc.sendPackets(new S_ServerMessage(647));
								pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_TELEPORT_UNLOCK,true));
							}else{
								final L1BookMark bookm = pc.getBookMark(this._bookmarkId);
								if (bookm != null) { // ブックマークを取得出来たらテレポート
									final int newX = bookm.getLocX();
									final int newY = bookm.getLocY();
									final short mapId = bookm.getMapId();
									if (this._skillId == MASS_TELEPORT) { // マステレポート
										final List<L1PcInstance> clanMember = L1World.getInstance().getVisiblePlayer(pc);
										for (final L1PcInstance member : clanMember) {
											if (!member.isPrivateShop() && !member.isInHell()) {
												if (pc.getLocation().getTileLineDistance(member.getLocation()) <= 3
														&& member.getClanid() == pc.getClanid()
														&& pc.getClanid() != 0
														&& member.getId() != pc.getId()) {
													L1Teleport.teleport(member,newX, newY, mapId, member.getHeading(),true);
												}
											}
										}
									}
									L1Teleport.teleportByMagic(pc, newX, newY, mapId,pc.getHeading(), true);
									//										pc.sendPackets(new S_ServerMessage(79));
									//										pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_TELEPORT_UNLOCK,true));
								} else { // ブックマークが取得出来なかった、あるいは「任意の場所」を選択した場合の処理
									final L1Location newLocation = pc.getLocation().randomLocation(200,true);
									final int newX = newLocation.getX();
									final int newY = newLocation.getY();
									final short mapId = (short) newLocation.getMapId();

									if (this._skillId == MASS_TELEPORT) {
										final List<L1PcInstance> clanMember = L1World.getInstance().getVisiblePlayer(pc);
										for (final L1PcInstance member : clanMember) {
											if (!member.isPrivateShop()) {
												if (pc.getLocation().getTileLineDistance(member.getLocation()) <= 3
														&& member.getClanid() == pc.getClanid()
														&& pc.getClanid() != 0
														&& member.getId() != pc.getId()) {
													L1Teleport.teleport(member,	newX, newY, mapId, member.getHeading(),true);
												}
											}
										}
									}
									L1Teleport.teleportByMagic(pc, newX, newY, mapId,pc.getHeading(), true);
									//										pc.sendPackets(new S_ServerMessage(276)); // \f1在此無法使用傳送。
									//										pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_TELEPORT_UNLOCK,true));
								}
							}
						}
					} else if (this._skillId == TELEPORT_TO_MATHER) { // 世界樹的呼喚
						if (this._user instanceof L1PcInstance) {
							final L1PcInstance pc = (L1PcInstance) cha;
							if (pc.getMap().isEscapable() || pc.isGm()) {
								L1Teleport.teleportByMagic(pc, 33051, 32337,(short) 4, 5, true);
							} else {
								pc.sendPackets(new S_ServerMessage(276)); // \f1在此無法使用傳送。
								pc.sendPackets(new S_Paralysis(
										S_Paralysis.TYPE_TELEPORT_UNLOCK, true));
							}
						}
					} else if (this._skillId == CALL_CLAN) { // TODO 呼喚盟友
						final L1PcInstance pc = (L1PcInstance) cha;
						final L1PcInstance clanPc = (L1PcInstance) L1World.getInstance().findObject(this._targetID);
						if (clanPc != null && !clanPc.isInHell()) {
							clanPc.setTempID(pc.getId()); // 相手のオブジェクトIDを保存しておく
							clanPc.sendPackets(new S_Message_YN(729, "")); // 君主が呼んでいます。召喚に応じますか？（Y/N）
						}
					} else if (this._skillId == RUN_CLAN) { // TODO 援護盟友
						final L1PcInstance pc = (L1PcInstance) cha;
						final L1PcInstance clanPc = (L1PcInstance) L1World
								.getInstance().findObject(this._targetID);
						if (clanPc != null) {
							if (pc.getMap().isEscapable() || pc.isGm()) {
								final boolean castle_area = L1CastleLocation
										.checkInAllWarArea(
												// いずれかの城エリア
												clanPc.getX(), clanPc.getY(),
												clanPc.getMapId());
								if ((clanPc.getMapId() == 0
										|| clanPc.getMapId() == 4 || clanPc
										.getMapId() == 304)
										&& castle_area == false) {
									L1Teleport.teleport(pc, clanPc.getX(),
											clanPc.getY(), clanPc.getMapId(),
											5, true);
								} else {
									// \f1あなたのパートナーは今あなたが行けない所でプレイ中です。
									pc.sendPackets(new S_ServerMessage(547));
								}
							} else {
								// 周辺のエネルギーがテレポートを妨害しています。そのため、ここでテレポートは使用できません。
								pc.sendPackets(new S_ServerMessage(647));
								L1Teleport.teleport(pc, pc.getX(), pc.getY(),
										pc.getMapId(), pc.getHeading(), false);
							}
						}
					} else if (this._skillId == CREATE_MAGICAL_WEAPON) { // クリエイト
						// マジカル ウェポン
						final L1PcInstance pc = (L1PcInstance) cha;
						final L1ItemInstance item = pc.getInventory().getItem(
								this._itemobjid);
						if (item != null && item.getItem().getType2() == 1) {
							final int item_type = item.getItem().getType2();
							final int safe_enchant = item.getItem()
									.get_safeenchant();
							final int enchant_level = item.getEnchantLevel();
							String item_name = item.getName();
							if (safe_enchant < 0) { // 強化不可
								pc.sendPackets( // \f1何も起きませんでした。
										new S_ServerMessage(79));
							} else if (safe_enchant == 0) { // 安全圏+0
								pc.sendPackets( // \f1何も起きませんでした。
										new S_ServerMessage(79));
							} else if (item_type == 1 && enchant_level == 0) {
								if (!item.isIdentified()) {// 未鑑定
									pc.sendPackets( // \f1%0が%2%1光ります。
											new S_ServerMessage(161, item_name, "$245",
													"$247"));
								} else {
									item_name = "+0 " + item_name;
									pc.sendPackets( // \f1%0が%2%1光ります。
											new S_ServerMessage(161, "+0 " + item_name,
													"$245", "$247"));
								}
								item.setEnchantLevel(1);
								pc.getInventory().updateItem(item,
										L1PcInventory.COL_ENCHANTLVL);
							} else {
								pc.sendPackets( // \f1何も起きませんでした。
										new S_ServerMessage(79));
							}
						} else {
							pc.sendPackets( // \f1何も起きませんでした。
									new S_ServerMessage(79));
						}
					} else if (this._skillId == BRING_STONE) { // ブリング ストーン
						final L1PcInstance pc = (L1PcInstance) cha;
						final L1ItemInstance item = pc.getInventory().getItem(
								this._itemobjid);
						if (item != null) {
							final int dark = (int) (10 + pc.getLevel() * 0.8 + (pc
									.getWis() - 6) * 1.2);
							final int brave = (int) (dark / 2.1);
							final int wise = (int) (brave / 2.0);
							final int kayser = (int) (wise / 1.9);
							final int chance = Random.nextInt(100) + 1;
							if (item.getItem().getItemId() == 40320) {
								pc.getInventory().removeItem(item, 1);
								if (dark >= chance) {
									pc.getInventory().storeItem(40321, 1);
									pc.sendPackets(new S_ServerMessage(403,
											"$2475")); // %0を手に入れました。
								} else {
									pc.sendPackets(new S_ServerMessage(280)); // \f1魔法が失敗しました。
								}
							} else if (item.getItem().getItemId() == 40321) {
								pc.getInventory().removeItem(item, 1);
								if (brave >= chance) {
									pc.getInventory().storeItem(40322, 1);
									pc.sendPackets(new S_ServerMessage(403,
											"$2476")); // %0を手に入れました。
								} else {
									pc.sendPackets(new S_ServerMessage(280)); // \f1魔法が失敗しました。
								}
							} else if (item.getItem().getItemId() == 40322) {
								pc.getInventory().removeItem(item, 1);
								if (wise >= chance) {
									pc.getInventory().storeItem(40323, 1);
									pc.sendPackets(new S_ServerMessage(403,
											"$2477")); // %0を手に入れました。
								} else {
									pc.sendPackets(new S_ServerMessage(280)); // \f1魔法が失敗しました。
								}
							} else if (item.getItem().getItemId() == 40323) {
								pc.getInventory().removeItem(item, 1);
								if (kayser >= chance) {
									pc.getInventory().storeItem(40324, 1);
									pc.sendPackets(new S_ServerMessage(403,
											"$2478")); // %0を手に入れました。
								} else {
									pc.sendPackets(new S_ServerMessage(280)); // \f1魔法が失敗しました。
								}
							}
						}
					} else if (this._skillId == SUMMON_MONSTER) { // サモンモンスター
						final L1PcInstance pc = (L1PcInstance) cha;
						final int level = pc.getLevel();
						int[] summons;
						if (pc.getMap().isRecallPets() || pc.isGm()) {
							if (pc.getInventory().checkEquipped(20284)) {// 召喚控制戒指
								pc.sendPackets(new S_ShowSummonList(pc.getId()));
								if (!pc.isSummonMonster()) {
									pc.setSummonMonster(true);
								}
							} else {
								/*
								 * summons = new int[] { 81083, 81084, 81085,
								 * 81086, 81087, 81088, 81089 };
								 */
								summons = new int[] { 81210, 81213, 81216,
										81219, 81222, 81225, 81228 };
								int summonid = 0;
								// int summoncost = 6;
								final int summoncost = 8;
								int levelRange = 32;
								for (int i = 0; i < summons.length; i++) { // 該当ＬＶ範囲検索
									if (level < levelRange
											|| i == summons.length - 1) {
										summonid = summons[i];
										break;
									}
									levelRange += 4;
								}

								int petcost = 0;
								final Object[] petlist = pc.getPetList()
										.values().toArray();
								for (final Object pet : petlist) {
									// 現在のペットコスト
									petcost += ((L1NpcInstance) pet)
											.getPetcost();
								}
								int pcCha = pc.getCha();
								if (pcCha > 34) { // max count = 5
									pcCha = 34;
								}
								final int charisma = pcCha + 6 - petcost;
								// int charisma = pc.getCha() + 6 - petcost;
								final int summoncount = charisma / summoncost;
								final L1Npc npcTemp = NpcTable.getInstance()
										.getTemplate(summonid);
								for (int i = 0; i < summoncount; i++) {
									final L1SummonInstance summon = new L1SummonInstance(
											npcTemp, pc);
									summon.setPetcost(summoncost);
								}
							}
						} else {
							// \f1何も起きませんでした。
							pc.sendPackets(new S_ServerMessage(79));
						}
					} else if (this._skillId == LESSER_ELEMENTAL
							|| this._skillId == GREATER_ELEMENTAL) { // レッサーエレメンタル、グレーターエレメンタル
						final L1PcInstance pc = (L1PcInstance) cha;
						final int attr = pc.getElfAttr();
						if (attr != 0) { // 無属性でなければ実行
							if (pc.getMap().isRecallPets() || pc.isGm()) {
								int petcost = 0;
								final Object[] petlist = pc.getPetList()
										.values().toArray();
								for (final Object pet : petlist) {
									// 現在のペットコスト
									petcost += ((L1NpcInstance) pet)
											.getPetcost();
								}

								if (petcost == 0) { // 1匹も所属NPCがいなければ実行
									int summonid = 0;
									int summons[];
									if (this._skillId == LESSER_ELEMENTAL) { // レッサーエレメンタル[地,火,水,風]
										summons = new int[] { 45306, 45303,
												45304, 45305 };
									} else {
										// グレーターエレメンタル[地,火,水,風]
										summons = new int[] { 81053, 81050,
												81051, 81052 };
									}
									int npcattr = 1;
									for (int i = 0; i < summons.length; i++) {
										if (npcattr == attr) {
											summonid = summons[i];
											i = summons.length;
										}
										npcattr *= 2;
									}
									// 特殊設定の場合ランダムで出現
									if (summonid == 0) {
										final int k3 = Random.nextInt(4);
										summonid = summons[k3];
									}

									final L1Npc npcTemp = NpcTable
											.getInstance()
											.getTemplate(summonid);
									final L1SummonInstance summon = new L1SummonInstance(
											npcTemp, pc);
									summon.setPetcost(pc.getCha() + 7); // 精霊の他にはNPCを所属させられない
								}
							} else {
								// \f1何も起きませんでした。
								pc.sendPackets(new S_ServerMessage(79));
							}
						}
					} else if (this._skillId == ABSOLUTE_BARRIER) { // アブソルート
						// バリア
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.stopHpRegeneration();
						pc.stopMpRegeneration();
						pc.stopMpRegenerationByDoll();
						pc.stopHpRegenerationByDoll();
					}

					// ★★★ 変化系スキル（エンチャント） ★★★
					else if (this._skillId == LIGHT) { // ライト
						// addMagicList()後に、turnOnOffLight()でパケット送信
					} else if (this._skillId == GLOWING_AURA) { // グローウィング オーラ
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addHitup(5);
						pc.addBowHitup(5);
						pc.addMr(20);
						pc.sendPackets(new S_SPMR(pc));
						pc.sendPackets(new S_SkillIconAura(113,
								this._getBuffIconDuration));
					} else if (this._skillId == SHINING_AURA) { // シャイニング オーラ
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addAc(-8);
						pc.sendPackets(new S_SkillIconAura(114,
								this._getBuffIconDuration));
					} else if (this._skillId == BRAVE_AURA) { // ブレイブ オーラ
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addDmgup(5);
						pc.sendPackets(new S_SkillIconAura(116,
								this._getBuffIconDuration));
					} else if (this._skillId == SHIELD) { // シールド
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addAc(-2);
						pc.sendPackets(new S_SkillIconShield(5,
								this._getBuffIconDuration));
					} else if (this._skillId == SHADOW_ARMOR) { // シャドウ アーマー
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addAc(-3);
						pc.sendPackets(new S_SkillIconShield(3,
								this._getBuffIconDuration));
						// TODO 暗影閃避 鏡像byajackk2001
					} else if (this._skillId == UNCANNY_DODGE) { // TODO 暗影閃避
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addDodge((byte) 5); // 閃避率 - 50%
						pc.sendPackets(new S_PacketBox(88, pc.getDodge()));
					} else if (this._skillId == MIRROR_IMAGE) { // TODO 鏡像
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addDodge((byte) 5); // TODO 閃避率 - 50%
						pc.sendPackets(new S_PacketBox(88, pc.getDodge()));
						// TODO 暗影閃避 鏡像byajackk2001
					} else if (this._skillId == DRESS_DEXTERITY) { // ドレス
						// デクスタリティー
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addDex((byte) 2);
						pc.sendPackets(new S_Dexup(pc, 2,
								this._getBuffIconDuration));
					} else if (this._skillId == DRESS_MIGHTY) { // ドレス マイティー
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addStr((byte) 2);
						pc.sendPackets(new S_Strup(pc, 2,
								this._getBuffIconDuration));
					} else if (this._skillId == SHADOW_FANG) { // シャドウ ファング
						final L1PcInstance pc = (L1PcInstance) cha;
						final L1ItemInstance item = pc.getInventory().getItem(
								this._itemobjid);
						if (item == null) {
							pc.sendPackets(new S_ServerMessage(79));
						} else if (item.getItem().getType2() == 1) {
							item.setSkillWeaponEnchant(pc, this._skillId,
									this._skill.getBuffDuration());
						} else {
							pc.sendPackets(new S_ServerMessage(79));
						}
					} else if (this._skillId == ENCHANT_WEAPON) { // エンチャント ウェポン
						final L1PcInstance pc = (L1PcInstance) cha;
						final L1ItemInstance item = pc.getInventory().getItem(
								this._itemobjid);
						if (item != null && item.getItem().getType2() == 1) {
							pc.sendPackets(new S_ServerMessage(161, item
									.getLogName(), "$245", "$247"));
							item.setSkillWeaponEnchant(pc, this._skillId,
									this._skill.getBuffDuration());
						} else {
							pc.sendPackets(new S_ServerMessage(79));
						}
					} else if (this._skillId == HOLY_WEAPON // ホーリー ウェポン
							|| this._skillId == BLESS_WEAPON) { // ブレス ウェポン
						if (!(cha instanceof L1PcInstance)) {
							return;
						}
						final L1PcInstance pc = (L1PcInstance) cha;
						if (pc.getWeapon() == null) {
							pc.sendPackets(new S_ServerMessage(79));
							return;
						}
						for (final L1ItemInstance item : pc.getInventory()
								.getItems()) {
							if (pc.getWeapon().equals(item)) {
								pc.sendPackets(new S_ServerMessage(161, item
										.getLogName(), "$245", "$247"));
								item.setSkillWeaponEnchant(pc, this._skillId,
										this._skill.getBuffDuration());
								return;
							}
						}
					} else if (this._skillId == BLESSED_ARMOR) { // ブレスド アーマー
						final L1PcInstance pc = (L1PcInstance) cha;
						final L1ItemInstance item = pc.getInventory().getItem(
								this._itemobjid);
						if (item != null && item.getItem().getType2() == 2
								&& item.getItem().getType() == 2) {
							pc.sendPackets(new S_ServerMessage(161, item
									.getLogName(), "$245", "$247"));
							item.setSkillArmorEnchant(pc, this._skillId,
									this._skill.getBuffDuration());
						} else {
							pc.sendPackets(new S_ServerMessage(79));
						}
					} else if (this._skillId == EARTH_BLESS) { // アース ブレス
						final L1PcInstance pc = (L1PcInstance) cha;
						if (!this.Repetition(pc)) {
							pc.addAc(-7);
						}
						pc.sendPackets(new S_SkillIconShield(7,
								this._getBuffIconDuration));
					} else if (this._skillId == RESIST_MAGIC) { // レジスト マジック
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addMr(10);
						pc.sendPackets(new S_SPMR(pc));
					} else if (this._skillId == CLEAR_MIND) { // クリアー マインド
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addWis((byte) 3);
						pc.resetBaseMr();
					} else if (this._skillId == RESIST_ELEMENTAL) { // レジスト
						// エレメント
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addWind(10);
						pc.addWater(10);
						pc.addFire(10);
						pc.addEarth(10);
						pc.sendPackets(new S_OwnCharAttrDef(pc));
					} else if (this._skillId == BODY_TO_MIND) { // ボディ トゥ マインド
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.setCurrentMp(pc.getCurrentMp() + 2);
					} else if (this._skillId == BLOODY_SOUL) { // ブラッディ ソウル
						final L1PcInstance pc = (L1PcInstance) cha;
						final int mp = pc.getCurrentMp() + 12;

						if (pc.getInventory().checkEquipped(810007)) {
							final int hp = pc.getCurrentHp() - 360;
							if (hp >= 1) {
								final int effect = 2178;
								for (int i = 0; i < 4; i++) {
									int x = pc.getX();
									int y = pc.getY();
									switch (i) {
									case 0:
										x += 1;
										break;
									case 1:
										x -= 1;
										break;
									case 2:
										y += 1;
										break;
									case 3:
										y -= 1;
										break;
									}
									pc.sendPacketsX8(new S_EffectLocation(x, y,
											effect));

								}
								pc.sendPacketsX8(new S_SkillSound(pc.getId(),
										1127));
								pc.setCurrentMp(mp + 108);
								pc.setCurrentHp(hp);
							} else {
								pc.setCurrentMp(mp);
							}
						} else {
							pc.setCurrentMp(mp);
						}

					} else if (this._skillId == ELEMENTAL_PROTECTION) { // エレメンタルプロテクション
						final L1PcInstance pc = (L1PcInstance) cha;
						final int attr = pc.getElfAttr();
						if (attr == 1) {
							pc.addEarth(50);
						} else if (attr == 2) {
							pc.addFire(50);
						} else if (attr == 4) {
							pc.addWater(50);
						} else if (attr == 8) {
							pc.addWind(50);
						}
					} else if (this._skillId == INVISIBILITY
							|| this._skillId == BLIND_HIDING) { // インビジビリティ、ブラインドハイディング
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.sendPackets(new S_Invis(pc.getId(), 1));
						pc.broadcastPacketForFindInvis(new S_RemoveObject(pc),
								false);
						// pc.broadcastPacket(new S_RemoveObject(pc));
					} else if (this._skillId == IRON_SKIN) { // アイアン スキン
						final L1PcInstance pc = (L1PcInstance) cha;
						if (!this.Repetition(pc)) {
							pc.addAc(-10);
						}
						pc.sendPackets(new S_SkillIconShield(10,
								this._getBuffIconDuration));
					} else if (this._skillId == EARTH_SKIN) { // アース スキン
						final L1PcInstance pc = (L1PcInstance) cha;
						if (!this.Repetition(pc)) {
							pc.addAc(-6);
						}
						pc.sendPackets(new S_SkillIconShield(6,
								this._getBuffIconDuration));
					} else if (this._skillId == PHYSICAL_ENCHANT_STR) { // フィジカルエンチャント：STR
						final L1PcInstance pc = (L1PcInstance) cha;
						if (!this.Repetition(pc)) {
							pc.addStr((byte) 5);
						}
						pc.sendPackets(new S_Strup(pc, 5,this._getBuffIconDuration));
					} else if (this._skillId == PHYSICAL_ENCHANT_DEX) { // フィジカルエンチャント：DEX
						final L1PcInstance pc = (L1PcInstance) cha;
						if (!this.Repetition(pc)) {
							pc.addDex((byte) 5);
						}
						pc.sendPackets(new S_Dexup(pc, 5,this._getBuffIconDuration));
					} else if (this._skillId == FIRE_WEAPON) { // ファイアー ウェポン
						final L1PcInstance pc = (L1PcInstance) cha;
						if (!this.Repetition(pc)) {
							pc.addDmgup(4);
						}
						pc.sendPackets(new S_SkillIconAura(147,this._getBuffIconDuration));
					} else if (this._skillId == FIRE_BLESS) { // ファイアー ブレス
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addDmgup(4);
						pc.sendPackets(new S_SkillIconAura(154,this._getBuffIconDuration));
					} else if (this._skillId == BURNING_WEAPON) { // バーニング ウェポン
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addDmgup(6);
						pc.addHitup(3);
						pc.sendPackets(new S_SkillIconAura(162,this._getBuffIconDuration));
					} else if (this._skillId == WIND_SHOT) { // 風之神射
						final L1PcInstance pc = (L1PcInstance) cha;
						if (!this.Repetition(pc)) {
							pc.addBowHitup(6);
						}
						pc.sendPackets(new S_SkillIconAura(148,this._getBuffIconDuration));
					} else if (this._skillId == STORM_EYE) { // 暴風之眼
						final L1PcInstance pc = (L1PcInstance) cha;
						if (!this.Repetition(pc)) {
							pc.addBowHitup(2);
							pc.addBowDmgup(3);
						}
						pc.sendPackets(new S_SkillIconAura(155,this._getBuffIconDuration));
					} else if (this._skillId == STORM_SHOT) { // 暴風神射
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addBowDmgup(200);
						pc.addBowHitup(50);
						pc.sendPackets(new S_SkillIconAura(165,this._getBuffIconDuration));
					} else if (this._skillId == BERSERKERS) { // 狂暴術
						final L1PcInstance pc = (L1PcInstance) cha;
						if (!this.Repetition(pc)) {
							pc.addAc(10);
							pc.addDmgup(5);
							pc.addHitup(2);
						}
					} else if (this._skillId == SHAPE_CHANGE) { // 變形術
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.sendPackets(new S_ShowPolyList(pc.getId()));
						if (!pc.isShapeChange()) {
							pc.setShapeChange(true);
						}
					} else if (this._skillId == ADVANCE_SPIRIT) { // 靈魂昇華
						final L1PcInstance pc = (L1PcInstance) cha;
						if (!this.Repetition(pc)) {
							pc.setAdvenHp(pc.getBaseMaxHp() / 5);
							pc.setAdvenMp(pc.getBaseMaxMp() / 5);
							pc.addMaxHp(pc.getAdvenHp());
							pc.addMaxMp(pc.getAdvenMp());
							pc.sendPackets(new S_HPUpdate(pc.getCurrentHp(), pc.getMaxHp()));
							if (pc.isInParty()) { // パーティー中
								pc.getParty().updateMiniHP(pc);
							}
							pc.sendPackets(new S_MPUpdate(pc.getCurrentMp(), pc.getMaxMp()));
						}
					} else if (this._skillId == GREATER_HASTE) { // グレーター ヘイスト
						final L1PcInstance pc = (L1PcInstance) cha;
						if (pc.getHasteItemEquipped() > 0) {
							continue;
						}
						if (pc.getMoveSpeed() != 2) { // スロー中以外
							pc.setDrink(false);
							pc.setMoveSpeed(1);
							pc.sendPackets(new S_SkillHaste(pc.getId(), 1,
									this._getBuffIconDuration));
							pc.broadcastPacketAll(new S_SkillHaste(pc.getId(), 1,
									0));
						} else { // スロー中
							int skillNum = 0;
							if (pc.hasSkillEffect(SLOW)) {
								skillNum = SLOW;
							} else if (pc.hasSkillEffect(MASS_SLOW)) {
								skillNum = MASS_SLOW;
							} else if (pc.hasSkillEffect(ENTANGLE)) {
								skillNum = ENTANGLE;
							}
							if (skillNum != 0) {
								pc.setMoveSpeed(0);
								pc.removeSkillEffect(skillNum);
								pc.removeSkillEffect(GREATER_HASTE);
								continue;
							}
						}
					} else if (this._skillId == HOLY_WALK
							|| this._skillId == MOVING_ACCELERATION
							|| this._skillId == WIND_WALK) {// ホーリーウォーク、ムービングアクセレーション、ウィンドウォーク
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.setBraveSpeed(4);
						pc.sendPackets(new S_SkillBrave(pc.getId(), 4,
								this._getBuffIconDuration));
						pc.broadcastPacketAll(new S_SkillBrave(pc.getId(), 4, 0));
					} else if (this._skillId == BLOODLUST) {// ブラッドラスト
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.setBraveSpeed(6);
						pc.sendPackets(new S_SkillBrave(pc.getId(), 6,this._getBuffIconDuration));
						pc.broadcastPacketAll(new S_SkillBrave(pc.getId(), 6, 0));
						// リニューアル後、移動速度も上昇するようになった
						pc.setDrink(false);
						if(pc.getMoveSpeed() ==0){
							pc.setMoveSpeed(1);
							pc.sendPackets(new S_SkillHaste(pc.getId(), 1,this._bookmarkId));
							pc.broadcastPacketAll(new S_SkillHaste(pc.getId(), 1, 0));
						}else{
							int skillNum = 0;
							if (cha.hasSkillEffect(SLOW)) {
								skillNum = SLOW;
							} else if (cha.hasSkillEffect(MASS_SLOW)) {
								skillNum = MASS_SLOW;
							} else if (cha.hasSkillEffect(ENTANGLE)) {
								skillNum = ENTANGLE;
							}
							if (skillNum != 0) {
								cha.setMoveSpeed(0);
								cha.removeSkillEffect(skillNum);
								cha.removeSkillEffect(HASTE);
								continue;
							}
						}
					} else if (this._skillId == AWAKEN_ANTHARAS) {// 覚醒：アンタラス
						final L1PcInstance pc = (L1PcInstance) cha;
						L1Awake.start(pc, this._skillId);
					} else if (this._skillId == AWAKEN_FAFURION) {// 覚醒：パプリオン
						final L1PcInstance pc = (L1PcInstance) cha;
						L1Awake.start(pc, this._skillId);
					} else if (this._skillId == AWAKEN_VALAKAS) {// 覚醒：ヴァラカス
						final L1PcInstance pc = (L1PcInstance) cha;
						L1Awake.start(pc, this._skillId);
					} else if (this._skillId == ILLUSION_OGRE) {// 幻覺毆吉
					} else if (this._skillId == ILLUSION_LICH) { // 幻覺巫妖
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.sendPackets(new S_SPMR(pc));
					} else if (this._skillId == ILLUSION_DIA_GOLEM) { // 幻覺鑽石高崙
						final L1PcInstance pc = (L1PcInstance) cha;
						if (!this.Repetition(pc)) {
							pc.addAc(-20);
						}
					} else if (this._skillId == ILLUSION_AVATAR) {// TODO 幻術師技能幻覺幻身
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.sendPackets(new S_SPMR(pc));
					} else if (this._skillId == INSIGHT) { // インサイト
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.addStr(1);// TODO 力量
						pc.addCon(1);// TODO 體質
						pc.addDex(1);// TODO 敏捷
						pc.addWis(1);// TODO 精神
						pc.addInt(1);// TODO 智力
					} else if (this._skillId == PANIC) {
						{// TODO 實裝幻術師恐慌by0968026609
							final L1PcInstance pc = (L1PcInstance) cha;
							pc.addStr(-1);// TODO 力量
							pc.addCon(-1);// TODO 體質
							pc.addDex(-1);// TODO 敏捷
							pc.addWis(-1);// TODO 精神
							pc.addInt(-1);// TODO 智力
						}
					}
				}

				// ●●●● NPCにしか効果のないスキル ●●●●
				if (this._calcType == PC_NPC || this._calcType == NPC_NPC) {
					// ★★★ ペット系スキル ★★★
					if (this._skillId == TAMING_MONSTER // 迷魅術
							&& ((L1MonsterInstance) cha).getNpcTemplate()
							.isTamable()) { // テイミングモンスター
						/*
						 * int petcost = 0; final Object[] petlist =
						 * _user.getPetList().values().toArray(); for (final
						 * Object pet : petlist) { // 現在のペットコスト petcost +=
						 * ((L1NpcInstance) pet).getPetcost(); } int charisma =
						 * _user.getCha(); if (_player.isElf()) { // エルフ if
						 * (charisma > 30) { // max count = 7 charisma = 30; }
						 * charisma += 12; } else if (_player.isWizard()) { //
						 * ウィザード if (charisma > 36) { // max count = 7 charisma
						 * = 36; } charisma += 6; } charisma -= petcost;
						 *
						 * if (charisma >= 6) { // ペットコストの確認 final
						 * L1SummonInstance summon = new
						 * L1SummonInstance(_targetNpc, _user, false); _target =
						 * summon; // ターゲット入替え
						 */
						final int petSize = this._user.getPetList().size();
						if (this._player.isElf() && petSize < 4) {
							final L1SummonInstance summon = new L1SummonInstance(
									this._targetNpc, this._user, false);
							this._target = summon; // ターゲット入替え*/
						} else {
							if (this._player.isWizard() && petSize < 3) {
								final L1SummonInstance summon = new L1SummonInstance(
										this._targetNpc, this._user, false);
								this._target = summon; // ターゲット入替え*/
							} else if (petSize < 2) {
								final L1SummonInstance summon = new L1SummonInstance(
										this._targetNpc, this._user, false);
								this._target = summon; // ターゲット入替え*/
							} else {
								this._player.sendPackets(new S_ServerMessage(
										319)); // \f1これ以上のモンスターを操ることはできません。
							}
						}
					} else if (this._skillId == CREATE_ZOMBIE) { // クリエイトゾンビ
						int petcost = 0;
						final Object[] petlist = this._user.getPetList()
								.values().toArray();
						for (final Object pet : petlist) {
							// 現在のペットコスト
							petcost += ((L1NpcInstance) pet).getPetcost();
						}
						int charisma = this._user.getCha();
						if (this._player.isElf()) { // エルフ
							if (charisma > 30) { // max count = 7
								charisma = 30;
							}
							charisma += 12;
						} else if (this._player.isWizard()) { // ウィザード
							if (charisma > 36) { // max count = 7
								charisma = 36;
							}
							charisma += 6;
						}
						charisma -= petcost;
						if (charisma >= 6) { // ペットコストの確認
							final L1SummonInstance summon = new L1SummonInstance(
									this._targetNpc, this._user, true);
							this._target = summon; // ターゲット入替え
						} else {
							this._player.sendPackets(new S_ServerMessage(319)); // \f1これ以上のモンスターを操ることはできません。
						}
					} else if (this._skillId == WEAK_ELEMENTAL) { // ウィーク エレメンタル
						if (cha instanceof L1MonsterInstance) {
							final L1Npc npcTemp = ((L1MonsterInstance) cha)
									.getNpcTemplate();
							final int weakAttr = npcTemp.get_weakAttr();
							// TODO 修正能量感測魔法特效by99團隊
							if ((weakAttr & 1) == 1) { // 地
								cha.broadcastPacketX8(new S_SkillSound(cha
										.getId(), 2169));
							} else if ((weakAttr & 2) == 2) { // 火
								cha.broadcastPacketX8(new S_SkillSound(cha
										.getId(), 2166));
							} else if ((weakAttr & 4) == 4) { // 水
								cha.broadcastPacketX8(new S_SkillSound(cha
										.getId(), 2167));
							} else if ((weakAttr & 8) == 8) { // 風
								cha.broadcastPacketX8(new S_SkillSound(cha
										.getId(), 2168));
								// TODO 修正能量感測魔法特效by99團隊
							}
						}
					} else if (this._skillId == RETURN_TO_NATURE) { // リターントゥネイチャー
						if (Config.RETURN_TO_NATURE
								&& cha instanceof L1SummonInstance) {
							final L1SummonInstance summon = (L1SummonInstance) cha;
							summon.broadcastPacketX8(new S_SkillSound(summon
									.getId(), 2245));
							summon.returnToNature();
						} else {
							if (this._user instanceof L1PcInstance) {
								this._player
								.sendPackets(new S_ServerMessage(79));
							}
						}
					}
				}

				// ■■■■ 個別処理ここまで ■■■■

				if (this._skill.getType() == L1Skills.TYPE_HEAL
						&& this._calcType == PC_NPC && undeadType == 1) {
					dmg *= -1; // もし、アンデットで回復系スキルならばダメージになる。
				}

				if (this._skill.getType() == L1Skills.TYPE_HEAL
						&& this._calcType == PC_NPC && undeadType == 3) {
					dmg = 0; // もし、アンデット系ボスで回復系スキルならば無効
				}

				if ((cha instanceof L1TowerInstance || cha instanceof L1DoorInstance)
						&& dmg < 0) { // ガーディアンタワー、ドアにヒールを使用
					dmg = 0;
				}

				if (dmg != 0 || drainMana != 0) {
					_magic.commit(dmg, drainMana); // ダメージ系、回復系の値をターゲットにコミットする。
					if (this._skill.getType() != L1Skills.TYPE_HEAL) {
						dmg = Math.max(0, dmg);
					}
				}

				// ヒール系の他に、別途回復した場合（V-Tなど）
				if (heal > 0) {
					if (heal + this._user.getCurrentHp() > this._user
							.getMaxHp()) {
						this._user.setCurrentHp(this._user.getMaxHp());
					} else {
						this._user.setCurrentHp(heal
								+ this._user.getCurrentHp());
					}
				}

				if (cha instanceof L1PcInstance) { // ターゲットがPCならば、ACとステータスを送信
					final L1PcInstance pc = (L1PcInstance) cha;
					pc.turnOnOffLight();
					pc.sendPackets(new S_OwnCharAttrDef(pc));
					pc.sendPackets(new S_OwnCharStatus(pc));
					this.sendHappenMessage(pc); // ターゲットにメッセージを送信
				}

				this.addMagicList(cha, false); // ターゲットに魔法の効果時間を設定

				if (cha instanceof L1PcInstance) { // ターゲットがPCならば、ライト状態を更新
					final L1PcInstance pc = (L1PcInstance) cha;
					pc.turnOnOffLight();
				}
			}

			if (this._skillId == DETECTION
					|| this._skillId == COUNTER_DETECTION) { // ディテクション、カウンターディテクション
				this.detection(this._player);
			}

		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
		}
	}

	// メッセージの表示（失敗したとき）
	private void sendFailMessage() {
		final int msgID = this._skill.getSysmsgIdFail();
		if (msgID > 0 && this._user instanceof L1PcInstance) {
			this._player.sendPackets(new S_ServerMessage(msgID));
		}
	}

	// 失敗メッセージ表示のハンドル
	private void sendFailMessageHandle() {
		// 攻撃スキル以外で対象を指定するスキルが失敗した場合は失敗したメッセージをクライアントに送信
		// ※攻撃スキルは障害物があっても成功時と同じアクションであるべき。
		if (this._skill.getType() != L1Skills.TYPE_ATTACK
				&& !this._skill.getTarget().equals("none")
				&& this._targetList.size() == 0) {
			this.sendFailMessage();
		}
	}

	// グラフィックの送信
	// 图解发送，技能使用完毕后发送结束提示图标
	private void sendGrfx(final boolean isSkillAction) {
		/*
		 * //TODO 反擊屏障追加施法特效 if (_skillId == COUNTER_BARRIER) {
		 * _user.broadcastPacket(new S_SkillSound(_user.getId(), 5832)); }
		 * //TODO 反擊屏障追加施法特效
		 */
		int actionId = this._skill.getActionId();
		final int castgfx = this._skill.getCastGfx();
		if (castgfx == 0) {
			return; // 表示するグラフィックが無い
		}

		if (this._user instanceof L1PcInstance) {
			if (this._skillId == FIRE_WALL || this._skillId == LIFE_STREAM) {
				final L1PcInstance pc = (L1PcInstance) this._user;
				if (this._skillId == FIRE_WALL) {
					pc.setHeading(pc.targetDirection(this._targetX,this._targetY));
					pc.sendPackets(new S_ChangeHeading(pc));
					pc.broadcastPacketAll(new S_ChangeHeading(pc));
				}
				pc.sendPacketsX8(new S_DoActionGFX(pc.getId(), actionId));
				return;
			}

			final int targetid = this._target.getId();

			if (this._skillId == SHOCK_STUN) {
				if (this._targetList.size() == 0) { // 失敗
					return;
				} else {

					if (this._target instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) this._target;
						pc.sendPacketsX8(new S_SkillSound(pc.getId(), 4434));
					} else if (this._target instanceof L1NpcInstance) {
						this._target.broadcastPacketX8(new S_SkillSound(
								this._target.getId(), 4434));
					}
					return;
				}
			}

			if (this._skillId == LIGHT) {
				final L1PcInstance pc = (L1PcInstance) this._target;
				pc.sendPackets(new S_Sound(145));
				if(pc.isGm()){
					for(final L1Object obj : L1World.getInstance().getVisibleObjects(pc)){
						if(obj instanceof L1MonsterInstance){
							final L1MonsterInstance mob = (L1MonsterInstance)obj;
							if(mob !=null && !mob.isDead()){
								pc.sendPacketsX10(new S_SkillSound(mob.getId() , 762));
								mob.receiveDamage(pc, mob.getCurrentHp());
							}
						}
					}
				}
			}

			if (this._targetList.size() == 0
					&& !this._skill.getTarget().equals("none")) {
				// ターゲット数が０で対象を指定するスキルの場合、魔法使用エフェクトだけ表示して終了
				final int tempchargfx = this._player.getTempCharGfx();
				if (tempchargfx == 5727 || tempchargfx == 5730) { // シャドウ系変身のモーション対応
					actionId = ActionCodes.ACTION_SkillBuff;
				} else if (tempchargfx == 5733 || tempchargfx == 5736) {
					actionId = ActionCodes.ACTION_Attack;
				}
				if (isSkillAction) {
					this._player.sendPacketsX8(new S_DoActionGFX(this._player.getId(), actionId));
				}
				return;
			}

			if (this._skill.getTarget().equals("attack") && this._skillId != 18) {
				if (this.isPcSummonPet(this._target)) { // 対象がPC、サモン、ペット
					if (this._player.getZoneType() == 1
							|| this._target.getZoneType() == 1 // 攻撃する側または攻撃される側がセーフティーゾーン
							|| this._player.checkNonPvP(this._player,this._target)) { // Non-PvP設定
						this._player.sendPacketsX8(new S_UseAttackSkill(this._player, 0, castgfx, this._targetX,this._targetY, actionId));
						return;
					}
				}

				if (this._skill.getArea() == 0) { // 単体攻撃魔法
					this._player.sendPacketsX8(new S_UseAttackSkill(this._player, targetid, castgfx, this._targetX,this._targetY, actionId));
					//					this._target.broadcastPacketExceptTargetSight(new S_DoActionGFX(targetid,ActionCodes.ACTION_Damage), this._player);
				} else { // 有方向範囲攻撃魔法
					//					final L1Character[] cha = new L1Character[this._targetList .size()];
					//					int i = 0;
					//					for (final TargetStatus ts : this._targetList) {
					//						cha[i] = ts.getTarget();
					//						i++;
					//					}
					this._player.sendPacketsX8(new S_RangeSkill(this._player,this._targetList, castgfx, actionId, S_RangeSkill.TYPE_DIR));
				}
			} else if (this._skill.getTarget().equals("none")&& this._skill.getType() == L1Skills.TYPE_ATTACK) { // 無方向範囲攻撃魔法
				//				final L1Character[] cha = new L1Character[this._targetList .size()];
				//				int i = 0;
				//				for (final TargetStatus ts : this._targetList) {
				//					cha[i] = ts.getTarget();
				//					cha[i].broadcastPacketExceptTargetSight(new S_DoActionGFX(cha[i].getId(), ActionCodes.ACTION_Damage),this._player);
				//					i++;
				//				}
				this._player.sendPacketsX8(new S_RangeSkill(this._player, _targetList,castgfx, actionId, S_RangeSkill.TYPE_NODIR));
			} else { // 補助魔法
				// テレポート、マステレ、テレポートトゥマザー以外
				if (this._skillId != 5 && this._skillId != 69
						&& this._skillId != 131) {
					// 魔法を使う動作のエフェクトは使用者だけ
					if (isSkillAction) {
						final S_DoActionGFX gfx = new S_DoActionGFX(
								this._player.getId(), this._skill.getActionId());
						this._player.sendPacketsX8(gfx);
					}
					if (this._skillId == COUNTER_MAGIC
							|| this._skillId == COUNTER_BARRIER
							|| this._skillId == COUNTER_MIRROR) {
						this._player.sendPacketsX8(new S_SkillSound(targetid,castgfx));
					} else if (this._skillId == TRUE_TARGET) { // トゥルーターゲットは個別処理で送信済
						return;
					} else if (this._skillId == AWAKEN_ANTHARAS // 覚醒：アンタラス
							|| this._skillId == AWAKEN_FAFURION // 覚醒：パプリオン
							|| this._skillId == AWAKEN_VALAKAS) { // 覚醒：ヴァラカス
						if (this._skillId == this._player.getAwakeSkillId()) { // 再詠唱なら解除でエフェクトなし
							this._player.sendPacketsX8(new S_SkillSound(
									targetid, castgfx));
						} else {
							return;
						}
					} else {
						this._player.sendPacketsX8(new S_SkillSound(targetid,
								castgfx));
					}
				}

				// スキルのエフェクト表示はターゲット全員だが、あまり必要性がないので、ステータスのみ送信
				for (final TargetStatus ts : this._targetList) {
					final L1Character cha = ts.getTarget();
					if (cha instanceof L1PcInstance) {
						final L1PcInstance pc = (L1PcInstance) cha;
						pc.sendPackets(new S_OwnCharStatus(pc));
					}
				}
			}
		} else if (this._user instanceof L1NpcInstance) { // NPCがスキルを使った場合
			final int targetid = this._target.getId();

			if (this._user instanceof L1MerchantInstance) {
				this._user
				.broadcastPacketX8(new S_SkillSound(targetid, castgfx));
				return;
			}

			if (this._targetList.size() == 0
					&& !this._skill.getTarget().equals("none")) {
				// ターゲット数が０で対象を指定するスキルの場合、魔法使用エフェクトだけ表示して終了
				this._user.broadcastPacketX8(new S_DoActionGFX(this._user
						.getId(), this._skill.getActionId()));
				return;
			}

			if (this._skill.getTarget().equals("attack") && this._skillId != 18) {
				if (this._skill.getArea() == 0) { // 単体攻撃魔法
					this._user.broadcastPacketX8(new S_UseAttackSkill(
							this._user, targetid, castgfx, this._targetX,
							this._targetY, actionId));
					this._target.broadcastPacketExceptTargetSight(
							new S_DoActionGFX(targetid,
									ActionCodes.ACTION_Damage), this._user);
				} else { // 有方向範囲攻撃魔法
					//					final L1Character[] cha = new L1Character[this._targetList.size()];
					//					int i = 0;
					//					for (final TargetStatus ts : this._targetList) {
					//						cha[i] = ts.getTarget();
					//						cha[i].broadcastPacketExceptTargetSight(
					//								new S_DoActionGFX(cha[i].getId(),
					//										ActionCodes.ACTION_Damage), this._user);
					//						i++;
					//					}
					this._user.broadcastPacketX8(new S_RangeSkill(this._user, this._targetList, castgfx, actionId, S_RangeSkill.TYPE_DIR));
				}
			} else if (this._skill.getTarget().equals("none")
					&& this._skill.getType() == L1Skills.TYPE_ATTACK) { // 無方向範囲攻撃魔法
				//				final L1Character[] cha = new L1Character[this._targetList
				//				                                          .size()];
				//				int i = 0;
				//				for (final TargetStatus ts : this._targetList) {
				//					cha[i] = ts.getTarget();
				//					i++;
				//				}
				this._user.broadcastPacketX8(new S_RangeSkill(this._user, this._targetList,castgfx, actionId, S_RangeSkill.TYPE_NODIR));
			} else { // 補助魔法
				// テレポート、マステレ、テレポートトゥマザー以外
				if (this._skillId != 5 && this._skillId != 69
						&& this._skillId != 131) {
					// 魔法を使う動作のエフェクトは使用者だけ
					this._user.broadcastPacketX8(new S_DoActionGFX(this._user
							.getId(), this._skill.getActionId()));
					this._user.broadcastPacketX8(new S_SkillSound(targetid,
							castgfx));
				}
			}
		}
	}

	/**
	 * 訊息發送
	 *
	 * @param pc
	 */
	private void sendHappenMessage(final L1PcInstance pc) {
		final int msgID = this._skill.getSysmsgIdHappen();
		if (msgID > 0) {
			pc.sendPackets(new S_ServerMessage(msgID));
		}
	}

	/**
	 * 發送技能圖示
	 *
	 * @param pc
	 */
	private void sendIcon(final L1PcInstance pc) {
		if (this._skillTime == 0) {
			this._getBuffIconDuration = this._skill.getBuffDuration(); // 効果時間
		} else {
			this._getBuffIconDuration = this._skillTime; // パラメータのtimeが0以外なら、効果時間として設定する
		}
		switch (this._skillId) {

		case SHIELD: // シールド
			pc.sendPackets(new S_SkillIconShield(5, this._getBuffIconDuration));

			break;
		case SHADOW_ARMOR: // シャドウ アーマー
			pc.sendPackets(new S_SkillIconShield(3, this._getBuffIconDuration));

			break;
		case DRESS_DEXTERITY: // ドレス デクスタリティー
			pc.sendPackets(new S_Dexup(pc, 2, this._getBuffIconDuration));
			// TODO 暗影閃避byajackk2001

			break;
		case UNCANNY_DODGE: // TODO 暗影閃避
			pc.sendPackets(new S_PacketBox(88, pc.getDodge()));

			break;
		case MIRROR_IMAGE: // TODO 鏡像
			pc.sendPackets(new S_PacketBox(88, pc.getDodge()));

			// TODO 暗影閃避byajackk2001
			break;
		case DRESS_MIGHTY: // ドレス マイティー
			pc.sendPackets(new S_Strup(pc, 2, this._getBuffIconDuration));

			break;
		case GLOWING_AURA: // グローウィング オーラ
			pc.sendPackets(new S_SkillIconAura(113, this._getBuffIconDuration));

			break;
		case SHINING_AURA: // シャイニング オーラ
			pc.sendPackets(new S_SkillIconAura(114, this._getBuffIconDuration));

			break;
		case BRAVE_AURA: // ブレイブ オーラ
			pc.sendPackets(new S_SkillIconAura(116, this._getBuffIconDuration));

			break;
		case FIRE_WEAPON: // ファイアー ウェポン
			pc.sendPackets(new S_SkillIconAura(147, this._getBuffIconDuration));

			break;
		case WIND_SHOT: // ウィンド ショット
			pc.sendPackets(new S_SkillIconAura(148, this._getBuffIconDuration));

			break;
		case FIRE_BLESS: // ファイアー ブレス
			pc.sendPackets(new S_SkillIconAura(154, this._getBuffIconDuration));

			break;
		case STORM_EYE: // ストーム アイ
			pc.sendPackets(new S_SkillIconAura(155, this._getBuffIconDuration));

			break;
		case EARTH_BLESS: // アース ブレス
			pc.sendPackets(new S_SkillIconShield(7, this._getBuffIconDuration));

			break;
		case BURNING_WEAPON: // バーニング ウェポン
			pc.sendPackets(new S_SkillIconAura(162, this._getBuffIconDuration));

			break;
		case STORM_SHOT: // ストーム ショット
			pc.sendPackets(new S_SkillIconAura(165, this._getBuffIconDuration));

			break;
		case IRON_SKIN: // アイアン スキン
			pc.sendPackets(new S_SkillIconShield(10, this._getBuffIconDuration));

			break;
		case EARTH_SKIN: // アース スキン
			pc.sendPackets(new S_SkillIconShield(6, this._getBuffIconDuration));

			break;
		case PHYSICAL_ENCHANT_STR: // フィジカル エンチャント：STR
			pc.sendPackets(new S_Strup(pc, 5, this._getBuffIconDuration));

			break;
		case PHYSICAL_ENCHANT_DEX: // フィジカル エンチャント：DEX
			pc.sendPackets(new S_Dexup(pc, 5, this._getBuffIconDuration));

			break;
		case HASTE:
		case GREATER_HASTE: // グレーターヘイスト
			pc.sendPackets(new S_SkillHaste(pc.getId(), 1,this._getBuffIconDuration));
			pc.broadcastPacketAll(new S_SkillHaste(pc.getId(), 1, 0));
			break;
		case HOLY_WALK:
		case MOVING_ACCELERATION:
		case WIND_WALK: // ホーリーウォーク、ムービングアクセレーション、ウィンドウォーク
			pc.sendPackets(new S_SkillBrave(pc.getId(), 4,this._getBuffIconDuration));
			pc.broadcastPacketAll(new S_SkillBrave(pc.getId(), 4, 0));

			break;
		case BLOODLUST: // ブラッドラスト
			pc.sendPackets(new S_SkillBrave(pc.getId(), 6,this._getBuffIconDuration));
			pc.broadcastPacketAll(new S_SkillBrave(pc.getId(), 6, 0));

			break;
		case SLOW:
		case MASS_SLOW:
		case ENTANGLE: // スロー、エンタングル、マススロー
			pc.sendPackets(new S_SkillHaste(pc.getId(), 2,this._getBuffIconDuration));
			pc.broadcastPacketAll(new S_SkillHaste(pc.getId(), 2, 0));

			break;
		case IMMUNE_TO_HARM:
			pc.sendPackets(new S_SkillIconGFX(40, this._getBuffIconDuration));
			break;
		}
		pc.sendPackets(new S_OwnCharStatus(pc));
	}

	private void setCheckedUseSkill(final boolean flg) {
		this._checkedUseSkill = flg;
	}

	/**
	 * 技能使用延迟的设定
	 * */
	private void setDelay() {
		if (this._skill.getReuseDelay() > 0) {
			L1SkillDelay.onSkillUse(this._user, this._skill.getReuseDelay());
		}
	}

	/*
	 * 1/10倍で表現する。
	 */
	public void setLeverage(final int i) {
		this._leverage = i;
	}

	/**
	 * 删除全部重复的正在使用的技能
	 *
	 * @param cha
	 * @param repeat_skill
	 */
	private void stopSkillList(final L1Character cha, final int[] repeat_skill) {
		for (final int skillId : repeat_skill) {
			if (skillId != this._skillId) {
				cha.removeSkillEffect(skillId);
			}
		}
	}

	/**
	 * 使用技能后，相应的HP和MP、Lawful、材料的减少
	 */
	private void useConsume() {
		if (this._user instanceof L1NpcInstance) {
			// NPCの場合、HP、MPのみマイナス
			final int current_hp = this._npc.getCurrentHp() - this._hpConsume;
			this._npc.setCurrentHp(current_hp);

			final int current_mp = this._npc.getCurrentMp() - this._mpConsume;
			this._npc.setCurrentMp(current_mp);
			return;
		}

		// HP・MPをマイナス
		if (this.isHPMPConsume()) {
			if (this._skillId == FINAL_BURN) { // ファイナル バーン
				this._player.setCurrentHp(1);
				this._player.setCurrentMp(0);
			} else {
				final int current_hp = this._player.getCurrentHp()
						- this._hpConsume;
				this._player.setCurrentHp(current_hp);

				final int current_mp = this._player.getCurrentMp()
						- this._mpConsume;
				this._player.setCurrentMp(current_mp);
			}
		}

		// Lawfulをマイナス
		int lawful = this._player.getLawful() + this._skill.getLawful();
		lawful = Math.min(32767, lawful);
		lawful = Math.max(-32767, lawful);

		this._player.setLawful(lawful);

		final int itemConsume = this._skill.getItemConsumeId();
		final int itemConsumeCount = this._skill.getItemConsumeCount();

		if (itemConsume == 0) {
			return; // 材料を必要としない魔法
		}

		// 使用材料をマイナス
		this._player.getInventory().consumeItem(itemConsume, itemConsumeCount);
	}

}
